[英]Understanding Tagged Types and asInstanceOf
我使用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 with { type Tag = MyTrait}
因为它像通常的String
对象一样被实例化。 asInstanceOf
方法的神奇之处是什么?
首先,请注意,标记类型的全部目的是为了避免运行时开销,但这也意味着您不能指望运行时类型检查可用于区分它们!
asInstanceOf
是一个运行时asInstanceOf
类型转换,并且JVM不知道Scala类型系统(甚至Java)。 它只有类,接口和基元。 因此, asInstanceOf
只能转换为已擦除类型,即与Scala类型最接近的JVM等效项。 String with { type Tag = MyTrait}
的String
擦除类型为String
,因此成功。
规范的相关部分是:
标准库将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() }
类型模式说明了x: String with { type Tag = MyTrait }
是如何匹配的:
非上述形式之一的类型也被接受为类型模式。 但是,这些类型模式将转换为它们的擦除。 Scala编译器将对这些模式发出“未经检查”的警告,以标记可能丢失类型安全性。
最后 ,
T1 with … with Tn {R}
擦除T1 with … with Tn {R}
的复合类型T1 with … with Tn {R}
就是T1,…,Tn
的交点控制符的擦除。
在这种情况下, T1
是String
, T2
是AnyRef { type Tag = MyTrait }
,因此您将获得String
和AnyRef
的交集主导AnyRef
,即String
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.