我们有一个特征Foo
,并且正在考虑一个方法cast
,该方法接受类型参数A <: Foo
和参数f: Foo
,如果f <: A
,则返回Some(f: A)
,否则返回None
:
trait Foo
def cast[A <: Foo](f: Foo): Option[A] = ???
如果Foo
扩展永远不会是通用的,那么附加ClassTag
是结论:
def cast[A <: Foo : ClassTag](f: Foo) = f match {
case f: A => Some(f)
case _ => None
}
...
class Bar extends Foo
class Hoo extends Foo
println cast[Bar](new Bar) //→ Some(Bar)
println cast[Hoo](new Bar) //→ None
但是如果存在一些具有抽象类型的Foo
呢?类似:
trait FooTyped extends Foo {
type T
}
那么cast
就完全被破坏了:
type FooT[A] = FooTyped{ type T = A }
...
val fint: FooT[Int] = new FooTyped{ type T = Int }
println cast[FooT[String]](fint) //→ Some(FooTyped) OH WHAT?
这是因为ClassTag
不关心类型参数和抽象类型。
所以我们将使用TypeTag
来跟踪它们…但我不知道具体是怎么做到的。
请帮我写完这篇文章:(
我认为答案是正确的。作为补充,我提供了一种可能的方法来实现这一点:
使用这个helper类:
class Caster[B : TypeTag](f: B) {
def cast[A <: Foo : TypeTag] =
if(typeOf[B] <:< typeOf[A]) Some(f) else None
}
你会得到这样的预期答案:
println(new Caster(new Bar).cast[Bar]) //→ Some(Bar)
println(new Caster(new Bar).cast[Hoo]) //→ None
println(new Caster(fint).cast[FooT[String]]) //→ None
Having:
trait Foo
def cast[A <: Foo](f: Foo): Option[A] = ???
您不仅需要TypeTag
作为目标类型A
,还需要TypeTag
作为值f
。JVM中的对象在运行时不携带完整的类型信息。