了解标记类型和asInstanceOf

时间:2016-04-21 20:33:06

标签: scala functional-programming scalaz

我使用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

我的问题是:如何?这怎么不抛出ClassCastexceptions.asInstanceOf[String @@ MyTrait]。从我的角度来看,"lala"是String类型但不是String with { type Tag = MyTrait}类型,因为它像通常的String对象一样被实例化。 asInstanceOf方法有什么神奇之处?

1 个答案:

答案 0 :(得分:4)

首先,请注意标记类型的重点是避免运行时开销,但这也意味着您不能期望运行时类型检查能够区分它们!

asInstanceOf是一个运行时强制转换,而JVM并不知道Scala类型系统(甚至是Java);它只有类,接口和基元。因此asInstanceOf只能转换为擦除的类型,即最接近Scora类型的JVM。已删除的String with { type Tag = MyTrait}类型为String,因此成功。

规范的相关部分是:

  1. 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()
    }
    
  2. Type patterns解释了x: String with { type Tag = MyTrait }如何匹配:

      

    不属于上述形式之一的类型也被接受为类型模式。但是,这种类型模式将被转换为它们的擦除。 Scala编译器将发出"未选中"警告这些模式标志着类型安全可能丧失。

  3. Finally

      

    复合类型T1 with … with Tn {R}的擦除是T1,…,Tn的交叉支配者的擦除。

    在这种情况下,T1StringT2AnyRef { type Tag = MyTrait },因此您获得了StringAnyRef的交集支配者,是String