简体   繁体   English

试图了解Scala中的ClassTag和TypeTag

[英]Trying to understand ClassTag and TypeTag in Scala

I am trying to understand how we can overcome type erasure in scala using ClassTag and TypeTag . 我试图了解如何使用ClassTagTypeTag克服scala中的类型擦除。 I wrote the following examples which are generic functions that try to filter out List[TNode] where TNode is equal to TMatch . 我编写了以下示例,这些示例是尝试过滤掉其中TNode等于TMatch List[TNode]通用函数。 However, I expect in recognizeUsingTypeTag , the function shall not call extractUsingClassTag is the generic type of list is equal to TMatch (or the message gets printed), but my assumption is apparently wrong. 不过,我希望在recognizeUsingTypeTag ,函数不得调用extractUsingClassTag是一般类型的列表等于TMatch (或者被打印的消息),但我的假设是错误的明显。 Thank you. 谢谢。

object Extractor {
  import scala.reflect.ClassTag

  def extractFail[TNode, TMatch](list: List[TNode]) = list.filter {
    case _: TMatch => true
    case _ => false
  }.map(x => x.asInstanceOf[TMatch])

  def extractUsingClassTag[TNode, TMatch](list: List[TNode])(implicit tag1: ClassTag[TNode], tag2: ClassTag[TMatch]) = list.filter {
    case _: TMatch => true
    case _ => false
  }.map(x => x.asInstanceOf[TMatch])

  import scala.reflect.runtime.universe._

  def recognizeUsingTypeTag[TNode, TMatch](list: List[TNode])(implicit tag1: TypeTag[TNode], tag2: TypeTag[TMatch], tag3: ClassTag[TNode], tag4: ClassTag[TMatch]) = list match {
    case _ if typeOf[TNode] =:= typeOf[TMatch] => {
      //
      // Why this does not get printed for List[String]
      //
      println("This should get printed when called for homogeneous")
      list.asInstanceOf[List[TMatch]]
    }
    case _ => extractUsingClassTag[TNode, TMatch](list)
  }
}

val homogeneous: List[String] = List("Hello", "World!")
val heterogeneous: List[Any] = List("Hello", "World!", 123, false)

println("extractFail")
println(Extractor.extractFail[Any, String](homogeneous))
println(Extractor.extractFail[Any, String](heterogeneous) + "\n")

println("extractUsingClassTag")
println(Extractor.extractUsingClassTag[Any, String](homogeneous))
println(Extractor.extractUsingClassTag[Any, String](heterogeneous) + "\n")

println("recognizeUsingTypeTag")
println(Extractor.recognizeUsingTypeTag[Any, String](homogeneous))
println(Extractor.recognizeUsingTypeTag[Any, String](heterogeneous) + "\n")

Console: 安慰:

extractFail
List(Hello, World!)
List(Hello, World!, 123, false)

extractUsingClassTag
List(Hello, World!)
List(Hello, World!)

recognizeUsingTypeTag
List(Hello, World!)
List(Hello, World!)

Why this does not get printed for List[String] 为什么不打印List [String]

Because you specified explicit type parameters: [Any, String] , so case _ if typeOf[TNode] =:= typeOf[TMatch] compares typeOf[Any] =:= typeOf[String] . 因为你指定了显式类型参数: [Any, String] ,所以case _ if typeOf[TNode] =:= typeOf[TMatch]比较typeOf[Any] =:= typeOf[String]

Since you do need to specify String for TMatch , but want TNode to be inferred, the usual way to do it is splitting type parameters into two lists by creating an intermediate class: 由于您确实需要为TMatch指定String ,但希望推断TNode ,通常的方法是通过创建中间类将类型参数拆分为两个列表:

// in Extractor
class RecognizeUsingTypeTag[TMatch : TypeTag : ClassTag] {
  def apply[TNode : TypeTag : ClassTag](list: List[TNode]) = list match {
    case _ if typeOf[TNode] =:= typeOf[TMatch] => {
      //
      // Why this does not get printed for List[String]
      //
      println("This should get printed when called for homogeneous")
      list.asInstanceOf[List[TMatch]]
    }
    case _ => extractUsingClassTag[TNode, TMatch](list)
  }
}

def recognizeUsingTypeTag[TMatch : TypeTag : ClassTag] = new RecognizeUsingTypeTag[TMatch]


println(Extractor.recognizeUsingTypeTag[String].apply(homogeneous)) // inferred as apply[String]
println(Extractor.recognizeUsingTypeTag[String].apply(heterogeneous) + "\n") // inferred as apply[Any]

When you have implicit parameters like that and don't need their names , it's preferred to use context bounds : T : TypeTag : ClassTag adds two implicit parameters of types TypeTag[T] and ClassTag[T] . 当你有这样的隐式参数并且不需要它们的名字时 ,最好使用上下文边界T : TypeTag : ClassTag添加两个类型为TypeTag[T]ClassTag[T]隐式参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM