Trait runtime type of type parameter through TypeTag when used with Existential type in Scala

删除回忆录丶 提交于 2019-12-06 16:47:11

The problem here is that typeT() is a method, so it will return a different value depending on your knowledge of the Animal. If the compiler can prove you have an Animal[Int], then it can easily get a TypeTag[Int]. But with an existential type in List[Animal[_]], you lose the type information contained in Animal. So when you select an arbitrary element from the list, all you know is that it's an Animal[_] when typeT is called, and nothing else. typeT does not know about the type parameter T for each instance. It has no way of proving it in this context.

The type cast of course works, because asInstanceof[Animal[Cat]] tells the compiler to forget what it knows. This if course can throw a ClassCastException when you get it wrong.

One way you can get it to work is by requiring the implicit TypeTag[T] on instantiation of an Animal[T], and storing that value, rather than resolving it within a method. Unfortunately, this means you cannot use a trait.

abstract class Animal[T](implicit tt: TypeTag[T]) {
    val tpe = tt.tpe
}

class Dog extends Animal[Int]
class Cat extends Animal[String]
val dog = new Dog
val cat = new Cat

scala> val aa: List[Animal[_]] = List(cat, dog, cat)
aa: List[Animal[_]] = List(Cat@5a9faacf, Dog@675c379d, Cat@5a9faacf)

scala> aa(0).tpe
res6: reflect.runtime.universe.Type = String

scala> aa(1).tpe
res7: reflect.runtime.universe.Type = Int

Alternatively, you could express it using a little syntactic sugar on the implicit parameters:

abstract class Animal[T: TypeTag] {
    val tpe = implicitly[TypeTag[T]].tpe
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!