【问题标题】:Non-variable type argument String in type Map[String,Any]Map[String,Any] 类型中的非变量类型参数 String
【发布时间】:2020-05-01 15:16:59
【问题描述】:

我有一个简单的方法可以从哈希图中检索嵌套键。我需要在Map[String,Any] 上进行模式匹配,以便我可以继续迭代嵌套数据,直到我得到一个平坦的值:

def get(map: Map[String, Any], key: String): Any = {
   var fields: mutable.Seq[String] = key.split('.')
   var currentKey: String = fields.head
   var currentValue: Any = map

   while (fields.nonEmpty && currentValue.isInstanceOf[Map[String, Any]]) {
     currentKey = fields.head
     fields = fields.drop(1)
     currentValue match {
       case m: Map[String, Any] => currentValue = m.getOrElse(currentKey, None)
       case _                   =>
     }
   }
   if (fields.nonEmpty) None else currentValue
 }

当我仅在 scala 中使用它时它可以工作,但如果它是从 java 调用的,我会收到错误 non-variable type argument String in type scala.collection.immutable.Map[String,Any]

我见过一些其他的解决方案,它们要求您重构代码并将地图包装在案例类中,但这会对依赖此方法的所有代码造成很大的破坏。有没有更简单的解决方法?

【问题讨论】:

  • 不小心被标记为js。感谢您的编辑!
  • 当您从 Java 中调用 Java Maps 时,您是如何将其转换为 Scala Maps 的?
  • 这是我仍在努力的事情,正在考虑使用HashMap<String, Object>。但现在我将它作为 json 传递并在使用 get() 之前自己反序列化它
  • 在这种情况下,错误可能出在创建Map 的代码中,而不是在此方法中。不要忘记编译器警告,它会告诉您类型匹配由于类型擦除而无法正常工作。

标签: scala type-conversion pattern-matching scala-java-interop


【解决方案1】:

由于类型擦除,您无法在 Map[String,Any] 上进行模式匹配。编译器会对此发出警告。此代码仅匹配 Map[_,_],因此它可以成功匹配任何密钥类型,而不仅仅是 String

所以该方法本质上是有缺陷的,从 Java 调用似乎暴露了使用 Scala 时没有出现的缺陷。

由于您还没有在 Java 中使用它,我会切换到 Java 代码的类型安全实现,然后尽快将遗留代码迁移到这个版本。虽然这可能具有破坏性,但它会修复引入错误代码的设计错误,因此应该尽早完成。 (每当您看到 Any 用作值类型时,很可能是设计在某个时候出错了)

类型安全的版本并不难,这里是一个大纲实现:

class MyMap[T] {
  trait MapType
  case class Value(value: T) extends MapType
  case class NestedMap(map: Map[String, MapType]) extends MapType

  def get(map: Map[String, MapType], key: String): Option[T] = {
    def loop(fields: List[String], map: Map[String, MapType]): Option[T] =
      fields match {
        case Nil =>
          None
        case field :: rest =>
          map.get(field).flatMap{
            case Value(res) => Some(res)
            case NestedMap(m) => loop(rest, m)
          }
      }

    loop(key.split('.').toList, map)
  }
}

实际上MyMap 应该实际保存Map 数据而不是将其传递给get,并且会有安全构建嵌套地图的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 2021-09-06
    • 2021-10-16
    • 2021-08-20
    • 2021-11-07
    • 2020-12-15
    相关资源
    最近更新 更多