我使用Miles Sabin gist的标记类型:
type Tagged[U] = { type Tag = U }
type @@[T, U] = T with Tagged[U]
trait MyTrait
def tag(s: String): String @@ MyTrait = s.asInstanceOf[String @@ MyTrait]
我可以这样使用(并且有效):
scala> tag("lala")
res7: @@[String,MyTrait] = lala
我的问题是:如何?这怎么不抛出ClassCastexception
:s.asInstanceOf[String @@ MyTrait]
。从我的角度来看,"lala"
是String类型但不是String with { type Tag = MyTrait}
类型,因为它像通常的String
对象一样被实例化。 asInstanceOf
方法有什么神奇之处?
答案 0 :(得分:4)
首先,请注意标记类型的重点是避免运行时开销,但这也意味着您不能期望运行时类型检查能够区分它们!
asInstanceOf
是一个运行时强制转换,而JVM并不知道Scala类型系统(甚至是Java);它只有类,接口和基元。因此asInstanceOf
只能转换为擦除的类型,即最接近Scora类型的JVM。已删除的String with { type Tag = MyTrait}
类型为String
,因此成功。
规范的相关部分是:
Standard Library定义asInstanceOf
如下:
/** Type cast; needs to be inlined to work as given */
def asInstanceOf[A]: A = this match {
case x: A => x
case _ => if (this eq null) this
else throw new ClassCastException()
}
Type patterns解释了x: String with { type Tag = MyTrait }
如何匹配:
不属于上述形式之一的类型也被接受为类型模式。但是,这种类型模式将被转换为它们的擦除。 Scala编译器将发出"未选中"警告这些模式标志着类型安全可能丧失。
复合类型
T1 with … with Tn {R}
的擦除是T1,…,Tn
的交叉支配者的擦除。
在这种情况下,T1
为String
,T2
为AnyRef { type Tag = MyTrait }
,因此您获得了String
和AnyRef
的交集支配者,是String
。