带类型的Scala对象如何丢失其类型?

时间:2019-02-19 19:19:18

标签: scala

在下面的代码段中,entities是我从其他代码段收到的Map[String, Seq[String]]对象。目标是将实体对象映射到两列的Spark DataFrame中。但是,在到达那里之前,我发现了一些非常不寻常的结果。

val data: Map[String, Seq[String]] = Map("idtag" -> Seq("things", "associated", "with", "id"))

println(data)
println(data.toSeq)
data.toSeq.foreach{println}
data.toSeq.map{case(id: String, names: Seq[String]) => names}.foreach{println}

val eSeq: Seq[(String, Seq[String])] = entities.toSeq

println(eSeq.head)
println(eSeq.head.getClass)
println(eSeq.head._1.getClass)
println(eSeq.head._2.getClass)

eSeq.map{case(id: String, names: Seq[String]) => names}.foreach{println}

上面在控制台上的输出是:

Map(idtag -> List(things, associated, with, id))
ArrayBuffer((idtag,List(things, associated, with, id)))
(idtag,List(things, associated, with, id))
List(things, associated, with, id)

(0CY4NZ-E,["MEC", "Marriott-MEC", "Media IQ - Kimberly Clark c/o Mindshare", "Mindshare", "WPP", "WPP Plc", "Wavemaker Global", "Wavemaker Global Ltd"])
class scala.Tuple2
class java.lang.String
class java.lang.String
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to scala.collection.Seq
        at package.EntityList$$anonfun$toStorage$4.apply(EntityList.scala:31)

我硬编码的data对象按预期方式工作。实体图上的.toSeq函数产生一个Seq(实现为ArrayBuffer)元组;这些元组可以通过映射进行处理。

但是使用entities对象,您可以看到,当我使用.head获取第一个元素时,它是一个Tuple2[String, String]。那怎么可能发生?元组的第二个元素如何变成字符串并引起异常?

如果最后一行更改为反映Tuple2[String, String],还会使我感到困惑:

eSeq.map{case(id: String, names: String) => names}.foreach{println}

然后我们得到一个编译错误:

/path/to/repo/src/main/scala/package/EntityList.scala:31: error: pattern type is incompatible with expected type;
  found   : String
  required: Seq[String]
     eSeq.map{case(id: String, names: String) => names}.foreach{println}

我无法用自己创建的Map[String, Seq[String]]复制这种奇怪的行为,如您在此代码中所见。谁能解释这种行为及其原因?

1 个答案:

答案 0 :(得分:2)

问题似乎是entities.toSeq在关于返回的数据类型的谎言,所以我要看“其他代码”并检查它是否做对了。

具体来说,它声称返回Seq[(String, Seq[String])]并且编译器相信它。但是getClass表明元组中的第二个对象实际上是java.lang.String而不是Seq[String]

如果这是正确的,则match语句将使用unapply提取值,然后在尝试将names转换为指定的类型时出错。

我注意到,该字符串似乎是[ ]中包含的字符串的列表,因此,创建entities的任何内容似乎都无法将其解析为{{ 1}},但声称它已经成功。