如何在Scala中从Map [String,Any]创建Map [String,String]?

7

Scala入门 - 如何从Map[String, Any]创建一个Map[String,String] Map[String,Any]的值是字符串,但我不知道如何将"Any"类型转换或以其他方式强制转换为"String"类型。


5
如果您知道它们是字符串,为什么编译器会认为它们是Any类型? - stew
我有一个函数,它从 case classes 中检索参数名称和值。 它返回 Map[String,Any],因为值可以是任何类型。 我习惯于Java,可以直接将其转换为所需的类型。 我发现我可以使用 'Any.asInstanceOf [String]' 来达到相同的效果。 - coolgar
4个回答

7

正如您所提到的,您的映射中所有的值都是字符串,因此您可以简单地使用asInstanceOf。如果您的假设不正确,则会收到如下所示的运行时异常:

$ scala
Welcome to Scala version 2.9.2 (OpenJDK 64-Bit Server VM, Java 1.7.0_55).
Type in expressions to have them evaluated.
Type :help for more information.

scala> val m:Map[String, Any] = Map("foo" -> 5, "bar" -> 7.6, "baz" -> "qux")
m: Map[String,Any] = Map(foo -> 5, bar -> 7.6, baz -> qux)

scala> val m2: Map[String, Any] = Map("foo" -> "5", "bar" -> "7.6", "baz" -> "qux")
m2: Map[String,Any] = Map(foo -> 5, bar -> 7.6, baz -> qux)

scala> m2.asInstanceOf[Map[String, String]]
res0: Map[String,String] = Map(foo -> 5, bar -> 7.6, baz -> qux)

当所有值实际上是String类型时,这非常完美。

scala> res0("foo")
res5: String = 5

请注意您可能存在的错误假设:

scala> m.asInstanceOf[Map[String, String]]
res2: Map[String,String] = Map(foo -> 5, bar -> 7.6, baz -> qux)

scala> res2("foo")
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at .<init>(<console>:10)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
    at java.lang.Thread.run(Thread.java:744)

3

如果你一开始就有一个Map[String, Any],那么这很可能是出现了问题的迹象,但是如果没有代码提供,我也无法帮助你。通常情况下,当你开始看到Any和其他超级通用类型被推断出来时,这意味着Scala的类型系统告诉你,你编写的代码并不是你想要的。

如果你真的想这样做,你可以这样做:

scala> val m = Map("foo" -> 5, "bar" -> 7.6, "baz" -> "qux")
m: scala.collection.immutable.Map[String,Any] = Map(foo -> 5, bar -> 7.6, baz -> qux)

scala> m.mapValues(_.toString)
res0: scala.collection.immutable.Map[String,String] = Map(foo -> 5, bar -> 7.6, baz -> qux)

这并不一定意味着代码出了问题,可能只是因为有人在他们的Scala代码中使用了Java库(例如ServletRequest参数映射)。 - Andrew Norman
因此,“可能”如此 :) 我同意有合法的理由使用Any,但我坚持认为这可能表明存在逻辑错误,并且推断出一些不相关类型的最小上界。 - acjay

2

正如其他人已经提到的那样,在第一次出现Any的情况下,这表明某处出了问题。正确的解决方法是找出出了什么问题并修复它。

然而,如果你真的想将所有值都转换为String(这是规避类型系统的做法,因此你不应该这样做),这里是如何实现:

val anyMap: Map[String, Any] = Map("foo" -> "bar", "baz" -> "qux")

val stringMap = anyMap.mapValues(_.asInstanceOf[String])
// => stringMap: Map[String, String] = Map(foo -> bar, baz -> qux)

0

编译器推断出的Map[String,Any]的示例包括

val a = Map( "s" -> 1, "t" -> "w" )
a: scala.collection.immutable.Map[String,Any] = Map(s -> 1, t -> w)

IntString的最不常见类型是Any

对映射中的每个值应用toString


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接