2013-12-18 6 views
1

Я только что начал экспериментировать с API-интерфейсом отражения, представленным в Scala 2.10, и ожидал, что код ниже будет оцениваться в пять раз (REPL).Scala reflection с TypeTags и одноточечными типами

К сожалению, действительно действительно только первое и последнее выражения. Может кто-нибудь объяснить, почему это так? Кажется, с точки зрения компилятора все эти сравнения типов одобрены или я ошибаюсь?

Есть ли способ сделать это (хотя бы один .type сравнение) работа?

import scala.reflect.runtime.universe._ 

class Test[A:TypeTag](val a:A) { 
    val value:this.type=this 
    def t1:TypeTag[Test[A]]=typeTag[Test[A]] 
    def t2:TypeTag[this.type]=typeTag[this.type] 
    def t3:TypeTag[_<:Test[A]]=typeTag[this.type] 
} 

val a:Test[String]=new Test("a") 

a.t1.tpe<:<typeOf[Test[String]] //works as expected 
a.t2.tpe<:<typeOf[Test[String]] //FAILS 
a.t3.tpe<:<typeOf[Test[String]] //FAILS 
a.t2.tpe<:<typeOf[a.type] //FAILS 
typeOf[a.type]<:<typeOf[a.type] //this works again 

Протестировано с помощью Scala REPL 2.10.3 и 2.11.0-M7.

С уважением,

Месси

ответ

1

Эфирное факт, чтобы помнить здесь является то, что одноэлементные типы не связаны с объектами (конкретные экземплярам). Скорее, они связаны с идентификаторами.

Это означает, что один объект может иметь несколько одноэлементных типов в зависимости от того, для какого идентификатора он назначен. Например:

class C { 
    val self = this 
    val thistpe = typeOf[this.type] 
    type T1 = this.type 
    type T2 = self.type 
} 

val c1 = new C 
val c2 = c1 
val c3: c1.type = c1 

val tpe1 = typeOf[c1.type] 
val tpe2 = typeOf[c2.type] 
val tpe3 = typeOf[c3.type] 
val tpe4 = typeOf[c1.T1] 
val tpe5 = typeOf[c1.T2] 
val tpe6 = c1.thistpe 

В приведенном выше фрагменте кода, tpe1, tpe3 и tpe4 будут будут признаны те же типы, но другие не будут.

В вашем случае, вы могли бы попробовать что-то вроде этого, вместо:

class C { 
    def thisTpe(implicit tag: TypeTag[this.type]) = tag.tpe 
} 

val c = new C 
c.thisTpe =:= typeOf[c.type] // yields true 
+0

Но разве это не так, что ваш пример также «не прошел статически» (val a: c2.type = c1)? Ваше решение, к сожалению, не то, что я искал, так как это было именно то, чего я хотел избежать: передавать информацию о типе со стороны. Цель была своего рода «неотъемлемо овеществленным» классом, т. Е. Который содержит информацию о своем типе). – messi

+0

@messi Да, извините, я не поймал все вопросы в вашем вопросе. Но я думаю, что факт по-прежнему остается фактом, что объект не может нести свою информацию типа _singleton_, поскольку он зависит от контекста, в котором используется этот объект. – ghik

2

Ваш класс не знает свой параметр типа, по-видимому. Возможно, ошибка в том, что ваш метод t2 не работает.

Спецификация говорит

Тип одноточечно р .type соответствует типу пути р.

Это все еще верно здесь, поскольку Test - всего лишь Test[A]. Но так как тег A доступен, вы можете подумать, что он его использует.

scala> typeTag[a.type].tpe 
res8: reflect.runtime.universe.Type = a.type 

scala> typeTag[a.type].tpe.widen 
res9: reflect.runtime.universe.Type = Test[String] 

scala> typeTag[a.type].tpe.widen <:< typeOf[Test[String]] 
res10: Boolean = true 

scala> typeTag[a.type].tpe <:< typeOf[Test[String]] 
res11: Boolean = true 

scala> a.t2.tpe 
res12: reflect.runtime.universe.Type = Test.this.type 

scala> a.t2.tpe.widen 
res13: reflect.runtime.universe.Type = Test[A] 
Смежные вопросы