2015-12-07 5 views
3

У меня есть зависимая от пути черта, объявляющая несколько модулей. Это нормально. Тем не менее, я пишу макрос, и мне нужно получить доступ к этим внутренним типам, и я не могу написать правильное выражение, выбирающее их.Проекция типа Scala: выберите объект в зависимом от пути значении

trait A { 

    type Foo 

    object module { // one of modules encapsulating functionality 

    class Bar // I use it as an annotation depending on Foo but that is irrelevant 
    } 

    class Other 
} 

Теперь мне нужно написать правильное выражение типа выбором Bar класса для извлечения его weakTypeTag. Я могу написать weakTypeOf[ A#Other ], чтобы выбрать класс Other. Но когда я пытаюсь выбрать Bar, он не работает. Я пробовал:

  • A#module.Bar
  • A#module#Bar
  • A#module.type.Bar
  • A#module.type#Bar

Все это терпят неудачу в выборе module.

Почему это не работает и как они работают? Благодарю.

ответ

4

module является объектом внутри A (это зависит от экземпляра A), поэтому этот объект A должен быть отражен в его типа подписи:

scala> typeOf[a.module.type forSome { val a: A }] 
res1: reflect.runtime.universe.Type = a.module.type forSome { val a: A } 

вы можете увидеть это путем создания псевдонима Inner внутри личностной A

trait A { 
    type Inner = module.type // it is actually this.module.type, where this refers to the instance of A 
    object module { 
    class Bar 
    } 
} 

теперь мы можем проверить, что эти два типа эквивалентны:

scala> typeOf[A#Inner] 
res2: reflect.runtime.universe.Type = _8.module.type forSome { val _8: A } 

scala> res1 =:= res2 
res3: Boolean = true 

Наконец, чтобы получить доступ к самым внутренним Bar, нам нужно добавить соответствующую проекцию:

scala> implicitly[(a.module.type forSome { val a: A })#Bar =:= A#Inner#Bar] 
res4: =:=[a.module.Bar,_38.module.Bar] = <function1> 
+0

Спасибо, большой ответ! Так что в принципе, с 'A # module.type # Bar' я был прав. Он просто не работает таким образом, поскольку отсутствует что-то вроде круглых скобок, не так ли? Вот почему я должен явно определять псевдоним типа, не так ли? (принять и +1) – Gaim

+0

Это хорошее наблюдение. AFAIK вообще, тип проекции не равен экзистенциальному типу. Учитывая вашу иерархию, 'неявно [A # Other =: = (a.Other forSome {val a: A})] дает ошибку. Хотя 'A # Inner' выглядит как проекция типа, на самом деле он представляет собой экзистенциальный тип, и выполняется равенство. – 4e6