从Map [String,Any]类型的Scala映射中提取值,其中Any可以是Map本身

时间:2013-07-13 21:55:49

标签: java scala map jvm

我有一个scala方法,如:

import collection.JavaConversions._ 

def foo(message: Map[String, Any]) {

  // message is implicitly converted to Java format
  someJavaApi.method1(message)

  message.get("mapField") match {
    case Some(mapField) => 
      val stringValue = mapField.asInstanceOf[Map[String, String]].get("internalField")
      otherJavaApi.method(stringValue)
    case None => /* do something */
  }
}

其中message是具有以下结构的地图:

Map(
   "field" -> "value",
   "mapField"-> Map("internalField"->"someValue")
)

从上面的代码可以明显看出,我有兴趣从“mapField”字典对象的“internalField”中提取“someValue”

但我一直在运行时收到错误,如:

scala.collection.JavaConversions$JMapWrapper cannot be cast to scala.collection.immutable.Map

我觉得是因为在调用第一个java库API时从scala到java集合的隐式转换,但我不确定,我想建议如何改进String值的提取“someValue “来自”mapField“,采用更多功能或Scala-ish方式,避免异常。

我正在使用scala 2.9.2版本。

2 个答案:

答案 0 :(得分:2)

Java映射是可变的,因此它们的Scala包装器是可变的.Map,而不是immutable.Map。

scala> Map("field" -> "value","mapField"-> Map("internalField"->"someValue"))
res0: scala.collection.immutable.Map[String,Object] = Map(field -> value, mapField -> Map(internalField -> someValue))

scala> import collection.JavaConverters._
import collection.JavaConverters._

scala> res0.mapValues { case m: Map[_,_] => m.asJava case x => x }
res2: scala.collection.immutable.Map[String,Object] = Map(field -> value, mapField -> {internalField=someValue})

scala> res0.asJava
res3: java.util.Map[String,Object] = {field=value, mapField=Map(internalField -> someValue)}

scala> .asScala
res4: scala.collection.mutable.Map[String,Object] = Map(field -> value, mapField -> Map(internalField -> someValue))

scala> .foreach { case (k, v: collection.Map[_,_]) => println(v.toList) case _ =>  }
List((internalField,someValue))

一些安全方面的帮助:

scala> :edit res0
+Map("field" -> Left("value"),"mapField"-> Right(Map("internalField"->"someValue")))
res6: scala.collection.immutable.Map[String,Product with Serializable with scala.util.Either[String,scala.collection.immutable.Map[String,String]]] = Map(field -> Left(value), mapField -> Right(Map(internalField -> someValue)))

scala> .mapValues { case Left(s) => s.length case Right(m) => m.values.map(_.length).sum }
res7: scala.collection.immutable.Map[String,Int] = Map(field -> 5, mapField -> 9)

答案 1 :(得分:0)

我尝试用你的代码制作一个有效的例子:

import collection.JavaConversions._

object Test extends App {

  object someJavaApi {
    def method1(message: java.util.Map[_, _]) { }
  }

  object otherJavaApi {
    def method(s: String) { }
  }

  def foo(message: Map[String, Any]) {

    // message is implicitly converted to Java format
    someJavaApi.method1(message)

    message.get("mapField") match {
      case Some(mapField) =>
        val stringValue = mapField.asInstanceOf[Map[String, String]]("internalField")
        otherJavaApi.method(stringValue)
      case None => /* do something */
    }
  }

  val message = Map(
    "field" -> "value",
    "mapField" -> Map("internalField" -> "someValue")
  )

  foo(message)

}

运行没有错误。

但我不知道如何在不编译代码的情况下回答这个问题。