这是类型参数定义和其他地方使用的下划线之间的混淆。中的下划线TypeTag[B[_]]
表示存在类型,因此您得到的标签不是 for B
,而是针对它的存在包装器,如果没有手动后处理,这几乎没有用。
因此typeOf[Funct[B, _]]
,需要一个原始标签B
不能使用包装器的标签并感到不安。生气是指它拒绝在范围内拼接标签并因编译错误而失败。如果你weakTypeOf
改用,那么那个会成功,但它会为所有无法拼接的东西生成存根,使结果对子类型检查无用。
看起来在这种情况下,我们真的达到了 Scala 的极限,因为我们无法在 Scala 中引用 raw B
,WeakTypeTag[B]
因为我们在 Scala 中没有善良的多态性。希望像DOT这样的东西可以让我们免于这种不便,但与此同时,您可以使用这种解决方法(它并不漂亮,但我无法想出更简单的方法)。
import scala.reflect.runtime.universe._
object Test extends App {
class Foo[B[_], T]
// NOTE: ideally we'd be able to write this, but since it's not valid Scala
// we have to work around by using an existential type
// def test[B[_]](implicit tt: WeakTypeTag[B]) = weakTypeOf[Foo[B, _]]
def test[B[_]](implicit tt: WeakTypeTag[B[_]]) = {
val ExistentialType(_, TypeRef(pre, sym, _)) = tt.tpe
// attempt #1: just compose the type manually
// but what do we put there instead of question marks?!
// appliedType(typeOf[Foo], List(TypeRef(pre, sym, Nil), ???))
// attempt #2: reify a template and then manually replace the stubs
val template = typeOf[Foo[Hack, _]]
val result = template.substituteSymbols(List(typeOf[Hack[_]].typeSymbol), List(sym))
println(result)
}
test[Option]
}
// has to be top-level, otherwise the substituion magic won't work
class Hack[T]
精明的读者会注意到我WeakTypeTag
在签名中使用了foo
,即使我应该可以使用TypeTag
。毕竟,我们在一个Option
行为良好的类型上调用 foo,因为它不涉及未解析的类型参数或对TypeTag
s 造成问题的本地类。不幸的是,由于https://issues.scala-lang.org/browse/SI-7686 ,它并不是那么简单,所以即使我们不需要,我们也被迫使用弱标签。