你不能使用:
a.flatMap({
case i: Int => List(i)
case l: List[Int] => l
})
case l: List[Int] 部分由于类型擦除而无法工作。事实上:
scala> val a = List(1, List("a"), 3)
a: List[Any] = List(1, List(a), 3)
scala> a.flatMap {
| case i: Int => List(i)
| case l: List[Int] => l
| }
<console>:11: warning: non-variable type argument Int in type pattern List[Int] (the underlying of List[Int]) is unchecked since it is eliminated by erasure
case l: List[Int] => l
^
res2: List[Int] = List(1, a, 3)
scala> res2(1) // boom!
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:105)
... 33 elided
在这些情况下,您可能需要考虑使用通过shapeless 获得的Typeable 类型类进行类型安全转换。例如:
scala> import shapeless.syntax.typeable._
import shapeless.syntax.typeable._
scala> val as = a.flatMap {
| case x: Int => List(x)
| case xs => xs.cast[List[Int]].getOrElse(List())
| }
as: List[Int] = List(1, 2, 3, 4)
scala> val b = List(1, 2, List("a", "b"), 3)
b: List[Any] = List(1, 2, List(a, b), 3)
scala> val bs = b.flatMap {
| case x: Int => List(x)
| case xs => xs.cast[List[Int]].getOrElse(List())
| }
bs: List[Int] = List(1, 2, 3)
cast[T] 方法可以通过 implicits 添加到每个类型,如果转换失败,则返回 Option[T],其值为 None,如果成功则返回 Some。
当然,如果您的第一个列表的内容不是Int 或List[Int],您当然可以决定失败。在我的示例中,我决定忽略其他类型并仍然生成 List[Int]。