2

我有一个像这样的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 集合的隐式转换,但我不确定,我想就如何改进从“mapField”,以更具功能性或 Scala 风格的方式并避免异常。

我正在使用 scala 2.9.2 版本。

4

2 回答 2

2

Java 映射是可变的,因此它们的 Scala 包装器是 mutable.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)
于 2013-07-14T01:25:44.853 回答
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)

}

那运行没有错误。

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

于 2013-07-13T22:21:08.300 回答