scala中的擦除消除:非变量类型参数未被选中,因为它通过擦除被消除

BSJ*_*BSJ 47 scala type-erasure

我有一个序列Seq [Any],其中包含各种对象(如String,Integer,List [String]等).我正在尝试筛选列表并将其分解为基于类类型分区的单独列表.以下是我在代码中使用的模式:

val allApis = mySequence.filter(_.isInstanceOf[String])
Run Code Online (Sandbox Code Playgroud)

这很好用,不会产生任何警告.但是,当我尝试过滤掉作为字符串列表的对象时:

val allApis = mySequence.filter(_.isInstanceOf[List[String]])
Run Code Online (Sandbox Code Playgroud)

我得到一个警告,说明列表[String]类型中的非变量类型参数String是未选中的,因为它被擦除消除了.现在,这项技术确实有效,我可以根据需要轻松过滤序列,但我想知道以恰当的方式处理警告的适当方法是什么,以便我知道我没有一个严重的错误潜伏在背景中等待爆炸

Rex*_*err 70

它不起作用,因为它将挑选出List[Double]任何其他列表List[String].有多种方法可以解决问题,包括将任何参数化类型包装在非参数化的case类中:

case class StringList(value: List[String])
Run Code Online (Sandbox Code Playgroud)

然后你就可以了

mySequence.collect{ case StringList(xs) => xs }
Run Code Online (Sandbox Code Playgroud)

拉出字符串列表(具有正确的类型,并且还安全地键入).

或者,如果您不想包装对象并希望确保它们的类型正确,则可以检查每个元素:

mySequence.filter( _ match {
  case xs: List[_] => xs.forall( _ match { case _: String => true; case _ => false })
  case _ => false
})
Run Code Online (Sandbox Code Playgroud)

虽然这甚至不会让你知道哪些类型的空列表应该是.

另一种可能性是将TypeTags 粘贴到列表中的所有内容; 这将阻止您需要手动包装东西.例如:

import scala.reflect.runtime.universe.{TypeTag, typeTag}
def add[A](xs: List[(Any, TypeTag[_])], a: A)(implicit tt: TypeTag[A]) = (a, tt) :: xs
val mySequence = add(add(add(Nil, List(42)), true), List("fish"))
mySequence.filter(_._2.tpe weak_<:< typeTag[List[String]].tpe)
Run Code Online (Sandbox Code Playgroud)


Vik*_*dya 10

val v = 1 ::"abc" :: true :: Nil
v : List[Any] = List(1,abc,true) 
Run Code Online (Sandbox Code Playgroud)

类型参数List类型已经统一到最大的共同的超类型的元素ListAny.

无形是救援.

import shapeless._
import HList._

val s = 1 :: "abc" :: true: HNil
s : shapeless.::[Int,shapeless.::[String,shapelsss.::[Boolean,shapeless.HNil]]]
= 1 :: abc :: true :: HNil
Run Code Online (Sandbox Code Playgroud)

使用Shapeless,HList您可以获得异构列表的编译时安全性.你现在可以filter以类型安全的方式.例如

s.filter[String]
Run Code Online (Sandbox Code Playgroud)