简体   繁体   English

Scala反射:上下文绑定的TypeTag与type参数不匹配

[英]Scala reflection: TypeTag from context bound doesn't match type parameter

Let's start with an example code: 让我们从一个示例代码开始:

import scala.reflect.runtime.universe._
class A[T] {
}
def foo[T: TypeTag](a: A[T]) {
  println(typeTag[T])
}
val a = new A[Int]
val b: A[_] = a
foo(a)
foo(b)

The output is: 输出为:

TypeTag[Int]
TypeTag[_$1]

Well, I have no clue whatsoever what is TypeTag[_$1] , but it sure looks fancy. 好吧,我不知道什么是TypeTag[_$1] ,但是看起来确实TypeTag[_$1] :) Still, I would think foo's expectations of the world are being violated here, as in if foo gets called with an instance of A[Int] then it is guaranteed to have the typetag for Int, and not some other obscure typetag. :)仍然,我认为foo对世界的期望在这里违反了,就像foo被A[Int]的实例调用一样,那么可以保证它具有Int的类型标签,而不是其他一些晦涩的类型标签。 Also, shouldn't typetags be "concrete" in contrast to weektypetags? 此外,与Weektypetags相比,Typetags是否应该“具体”?

Now of course I see that the compiler cannot tell in the second foo call the type parameter of A. So my expectation wasn't that I magically get typeTag[Int] as the output of the second call, but rather I was hoping for a compile time error. 现在,我当然知道编译器无法在第二个foo调用中告诉A的类型参数。因此,我的期望不是我神奇地将typeTag[Int]作为第二个调用的输出,但是我希望编译时错误。

Where is my missunderstanding? 我的误会在哪里?

Some futile speculation One could argue that what's going on is a call to foo with argument type A[_] , or, to make it more explicit, the existential type A[S] forSome { type S } . 徒劳的猜测人们可能会争辩说,正在发生的事情是使用参数类型A[_]调用foo,或者更明确地说,是存在性类型A[S] forSome { type S } An then the typeTag captures the "_" somehow. 然后,typeTag以某种方式捕获“ _”。 But this doesn't really make sense, as foo expects A[T] for some concrete T , and the above existential type is not A[T] for any concrete T . 但这并没有真正的意义,因为foo对某些具体的T期望A[T] ,而对于任何具体的T ,上述存在类型都不是A[T] Or maybe a call with an argument A[Any] ? 还是带有参数A[Any]的呼叫? But then why not TypeTag[Any] , and even more severely, A is not covariant, so this would also be plain wrong. 但是,为什么不选择TypeTag[Any] ,更严重A是, A不是协变的,所以这也是完全错误的。

Btw, I'm using scala 2.10. 顺便说一句,我正在使用scala 2.10。

Type tags are created at compile time, and values are not available at compile time. 类型标签在编译时创建,而值在编译时不可用。 Once you cast an A[Int] to the existential type A[_] , all information about the type parameter has been lost. 一旦将A[Int]转换为现有类型A[_] ,有关类型参数的所有信息都将丢失。

If they were created at run-time, based on values, type erasure would make it impossible to know A 's parameter. 如果它们是在运行时根据值创建的,则类型擦除将使不可能知道A的参数。 Even something that is known to be an A[Int] at compile-time is at best an A[Object] at run-time (unless A is Array , but let's not go there). 即使在编译时被称为A[Int]东西最多在运行时也不过是A[Object] (除非AArray ,但不要去那里)。

So your speculation is correct, for foo(b) , the type parameter is indeed the _ from the existential A[_] , and that anonymous type variable prints as _$1 . 所以,你的猜测是正确的,对于foo(b)类型参数确实是_从生存A[_]和匿名类型变量打印为_$1

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

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