【问题标题】:Scala reflection: TypeTag from context bound doesn't match type parameterScala 反射:来自上下文绑定的 TypeTag 与类型参数不匹配
【发布时间】:2014-06-18 11:53:19
【问题描述】:

让我们从一个示例代码开始:

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)

输出是:

TypeTag[Int]
TypeTag[_$1]

好吧,我不知道TypeTag[_$1] 是什么,但它确实看起来很漂亮。 :) 尽管如此,我认为 foo 对世界的期望在这里被违反了,如果 foo 被一个 A[Int] 的实例调用,那么它保证有 Int 的类型标签,而不是其他一些晦涩的类型标签。另外,与 weektypetags 相比,typetags 不应该是“具体的”吗?

现在我当然看到编译器在第二次 foo 调用中无法分辨出 A 的类型参数。所以我的期望不是我神奇地将 typeTag[Int] 作为第二次调用的输出,而是我希望编译时错误。

我的误解在哪里?

一些徒劳的猜测 有人可能会争辩说,正在发生的事情是使用参数类型 A[_] 调用 foo,或者更明确地说,是存在类型 A[S] forSome { type S }。然后 typeTag 以某种方式捕获“_”。但这并没有真正的意义,因为 foo 期望 A[T] 用于某些具体的T,而上述存在类型不是A[T] 用于任何具体的T。 或者可能是带有参数A[Any] 的调用?但是为什么不是TypeTag[Any],更严重的是,A 不是协变的,所以这也是完全错误的。

顺便说一句,我使用的是 scala 2.10。

【问题讨论】:

    标签: scala reflection


    【解决方案1】:

    类型标签是在编译时创建的,而值在编译时不可用。一旦将 A[Int] 强制转换为存在类型 A[_],有关类型参数的所有信息都将丢失。

    如果它们是在运行时创建的,基于值,类型擦除将无法知道A 的参数。即使是在编译时已知为 A[Int] 的东西,在运行时也最多是 A[Object](除非 AArray,但我们不要去那里)。

    所以你的猜测是正确的,对于foo(b),类型参数确实是存在性A[_] 中的_,并且该匿名类型变量打印为_$1

    【讨论】:

    • 我知道类型标签是在编译时生成的,而且我也知道擦除,这正是我期待编译时错误的原因。不能为 b 创建匹配的类型标记就可以了。对我来说似乎不太好的是编译器仍然尝试并生成我认为违反 foo 签名的东西。为了让您的解决方案清楚问题:第二次调用 foo 时类型参数 T 的值是多少?并且不要说'_',因为没有这种类型。
    • _ 本身不是类型,但它是一个占位符,表示“这里有一个类型,但我不在乎/不知道它是什么”。但是,编译器正在跟踪一个类型 _$1,并且编译器仍然可以提供有关包含 _ 的类型的有用信息,例如(_, _)(S, S) forSome { type S } 不同。
    • 好吧,让我们继续这个假设。首先,你会说_$1是一个具体类型吗?我可以看到编译器内部有这样的类型别名或通配符,但这在我看来绝对不是一个具体的类型,比如 Int。 (API 文档说 TypeTag 始终是一个具体类型,不像 WeekTypeTags,但我不得不承认具体的定义对我来说并不清楚。)
    • 第二,TypeTag[_$1]TypeTag[Int]是什么关系?综上所述,我敢说一定没有什么特别的,因为编译器在创建这个类型标签时对 Int 一无所知,对吧?现在的承诺是 foo 将收到一个 A[T] 和一个 TypeTag[T] 用于 same T。当它接收到 b 时,它是 A[Int] 的一个实例,A 是不变的,T 只能是 Int。因此,承诺是 foo 接收 TypeTag[Int] 的实例。因此,我们可以得出结论,typeTag[$_1]TypeTag[Int] 的一个实例。这是正确的思路吗?
    • 是的,它是具体的。区别与类型参数和抽象类型成员有关。考虑def bar[T](a: A[T]) = foo(a)。这失败了,因为T 不是具体的,因此无法生成类型标记。如果foo 只需要WeakTypeTag,它会起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    相关资源
    最近更新 更多