【问题标题】:How to create a Map[String,String] from Map[String, Any] in Scala?如何在 Scala 中从 Map[String, Any] 创建 Map[String,String]?
【发布时间】:2014-10-09 04:05:58
【问题描述】:

Scala 新手 - 如何从 Map[String, Any] 创建 Map[String,String] Map[String,Any] 的值是字符串,但我不知道如何将“Any”类型强制转换为“String”类型。

【问题讨论】:

  • 如果你知道它们是字符串,为什么编译器会认为它们是 Any?
  • 我有一个从案例类中检索参数名称和值的函数。它将它们作为 Map[String,Any] 返回,因为这些值可以是任何类型。我已经习惯了 Java,在那里我可以转换为我想要的类型。我发现我可以使用 'Any.asInstanceOf[String]' 来获得相同的效果。

标签: scala map any


【解决方案1】:

正如您提到的,您的地图中的所有值都是字符串,您可以简单地使用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)

【讨论】:

    【解决方案2】:

    首先有一个Map[String, Any] 是一个迹象,有些事情可能已经偏离轨道,虽然没有任何代码可以查看,但我真的无法帮助你。通常,当您开始看到 Anys 和其他超泛型类型的推断时,是 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 参数映射)
    • @AndrewNorman 因此“可能” :) 我同意拥有Any 的正当理由,但我坚持认为它可能表明存在逻辑错误和最低上限被推断出一些不相关的类型。
    【解决方案3】:

    编译器推断的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 应用于映射中的每个值。

    【讨论】:

      【解决方案4】:

      正如其他人已经提到的那样,首先拥有Any 的事实表明某处出现了问题。正确的解决方案是找出哪里出了问题并修复它。

      但是,如果您真的想要将所有值强制转换为 Strings(这是在规避类型系统,因此您不应该这样做) ,这是你的做法:

      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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-07-21
        • 2015-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-18
        • 1970-01-01
        相关资源
        最近更新 更多