我目前正在处理需要Java类型的AWS Java SDK。
我一直在使用JavaConverters
将地图和列表等类型显式转换为java。我一直在遇到越来越复杂的类型,并发现自己不得不深入查看变得笨拙的列表。
我当前的问题是我有一个Map[String, List[String]]
将整个对象转换为java很简单,但是当匹配地图中的列表时,我会被类型擦除命中。
val t = m.map{
case (k, v: List[String]) => k -> v //type erasure so unreachable
}
我在Scala中找到了一个很好的解释Type Tags,这是我想要实现的优雅解决方案。 Scala: What is a TypeTag and how do I use it?
我只是不确定我是如何在模式匹配中实现这一点的。
我实现了一个看起来像这样的方法
def isNestedMap[A : TypeTag](xs: A): Boolean = typeOf[A] match {
case t if t =:= typeOf[Map[String, List[String]]] => true
case t => false
}
新案例case (k, v) if isNestedMap(v) => k -> "beans"
但是这总是返回false,因为我的方法将类型视为Any
。
任何想法如何超越这个?或者更好的方法是将深度列表或映射递归转换为它们的java等价物?
谢谢大家。
编辑:Map实际上是Map[String, Any]
的一种类型,所以在将其转换为Java之前我需要知道Any
的类型
答案 0 :(得分:2)
我认为你的问题与擦除无关,甚至不需要使用类型标签。以下是关于REPL的快速会话,演示了一种进行转换的方法:
{{1}}
答案 1 :(得分:1)
编译器根据静态类型插入编辑:Map实际上是一种Map [String,Any],所以在将其转换为Java之前我需要知道Any的类型
TypeTag
,因此当您调用isNestedMap(v)
时,它会看到v: Any
并插入isNestedMap[Any](v)(typeTag[Any])
。
或者更好的方法是递归地将深层列表或地图转换为它们的java等价物?
像
这样的东西def deepAsJava(x: Any): Any = x match {
case l: List[_] => l.map(deepAsJava).asJava
case m: Map[_, _] => m.map { case (k, v) => (k, deepAsJava(v)) }.asJava
case ... // other collections you want to support
case x => x
}
您可以将其拆分为listDeepAsJava
等单独的函数,以便为每个函数获取更好的类型签名:
def deepAsJava(x: Any): Any = x match {
case l: List[_] => listDeepAsJava(l)
case m: Map[_, _] => mapDeepAsJava(m)
case ... // other collections you want to support
case x => x
}
def listDeepAsJava(x: List[Any]): java.util.List[Any] = l.map(deepAsJava).asJava
...
答案 2 :(得分:0)
尝试使用Array
代替List
。
val m = Map[String, Array[String]]()
val t = m.map{
case (k, v: Array[String]) => k -> v //no type erasure
}