类型 Map[String,Any] 中的非变量类型参数 String

Non-variable type argument String in type Map[String,Any]

我有一个简单的方法可以从哈希图中检索嵌套键。我需要在 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]

我见过一些其他解决方案,这些解决方案要求您重构代码并将地图包装在一个案例中 class,但这对所有依赖此方法的代码来说都是非常具有破坏性的。有没有更简单的修复方法?

由于类型擦除,您无法在 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,并且会有安全构建嵌套地图的方法。