2016-04-21 8 views
1

Я использую маркированные типы из Miles Sabin сутью:Понимание Tagged Типы и asInstanceOf

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?

+1

'{type Tag = MyTrait}' на самом деле не существует во время выполнения, он полностью стирается и учитывается только компилятором Scala. – pedrofurla

+0

так что происходит во время выполнения, когда вызывается 's.asInstanceOf [String @@ MyTrait]'? – ka4eli

ответ

4

Прежде всего, обратите внимание на то, что вся точка помеченных типов заключается в том, чтобы избежать накладных расходов во время выполнения, но это также означает, что вы не можете ожидать, что проверки типов выполнения будут работать для их различения!

asInstanceOf - это время выполнения, а JVM не знает систему типа Scala (или даже Java); он имеет только классы, интерфейсы и примитивы. Таким образом, asInstanceOf может передавать только стираемый тип, т. Е. Ближайший эквивалент JVM типа Scala. Стираемый тип 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.

    В этом случае T1 является String, T2AnyRef { type Tag = MyTrait } это, так что вы получите пересечение доминатором String и AnyRef, который String.

+0

поэтому после типа erasure 's.asInstanceOf [String @@ MyTrait]' становится 's.asInstanceOf [String]'? – ka4eli

+1

@ ka4eli Да. То же самое для 'isInstanceOf', сопоставление шаблонов и т. Д. –

+0

@ ka4eli Я расширил ответ с некоторыми деталями. –