2015-04-01 2 views
2

Мой сценарий как:Ссылаясь абстрактный элемент типа параметра типа

trait A { 
    type B 
    def foo(b: B) 
} 

trait C[D <: A] { 
    val d: D 
    def createB(): D#B 
    def bar() { 
     d.foo(createB) 
    } 
} 

В РЕПЛ, он жалуется

<console>:24: error: type mismatch; 
found : D#B 
required: C.this.d.B 
     a.bar(createB()) 

Что случилось с этим? И (если возможно вообще), как исправить этот код?

ответ

3

D#B - это проекция типа, и это не то же самое, что и d.B. У вас есть несоответствие типа, потому что в foo, B фактически означал this.B, который, как сказано, не совпадает с D#B (последний более общий). неформально, вы можете думать о D#B как представляющие любой возможный типа, что абстрактный тип B может принять для любого экземпляра D, а d.B является типом B для конкретного экземпляра d.

См. What does the `#` operator mean in Scala? и What is meant by Scala's path-dependent types? для некоторых контекстов.

Один из способов сделать это скомпилировать это путем изменения createB «s типа возврата к d.B:

def createB(): d.B 

Однако во многих случаях такого решения является слишком ограничительным, потому что вы привязаны к конкретному экземпляру d, который возможно, не то, что вы имели в виду. Другим решением является то, чтобы заменить абстрактный тип с параметром типа (хотя это более подробно):

trait A[B] { 
    def foo(b: B) 
} 

trait C[B, D <: A[B]] { 
    val d: D 
    def createB(): B 
    def bar() { 
    d.foo(createB) 
    } 
} 
0

Updateдал this answer Я не уверен, следует ли это считать ошибку или не

Это ошибка: SI-4377. Явный тип приписывание дает

trait C[D <: A] { 
    val d: D 
    def createB(): D#B 
    def bar() { 
    (d:D).foo(createB) 
     // [error] found : D#B 
     // [error] required: _3.B where val _3: D 
    } 
} 

, который выглядит как протечки реализации. Существует обходное решение, которое включает в себя литье к типу пересечения (опасно, отливка неверна и т. Д., См. Мой другой ответ here)

trait A { 
    type B 
    def foo(b: B) 
} 
case object A { 
    type is[A0 <: A] = A0 { 
    type B = A0#B 
    } 
    def is[A0 <: A](a: A0): is[A0] = a.asInstanceOf[is[A0]] 
} 

trait C[D <: A] { 
    val d: D 
    def createB(): D#B 
    def bar() { 
    A.is(d).foo(createB) // use it here! 
    } 
}