2013-01-11 13 views
5

I-Code haben:Fehler bei Definition kovarianten und kontra Typen

class A { 
    override def toString = "object class A" 
} 

class B extends A { 
    override def toString = "object class B" 
} 

class Cell[+T](init: T) { 
    private[this] var current: T = init 
    def get: T = current 
    def set(x: T) { current = x } 
} 

val cB = new Cell[B](new B) 
println(cB.get) 
val cA: Cell[A] = cB 
println(cA.get) 

aber ich habe Fehler in Zeile: def set(x: T) { current = x }

error: covariant type T occurs in contravariant position in type T of value x def set(x: T) { current = x }

Erklären Sie bitte

+1

Zusätzlich zu den aufschlussreichen Antworten, warum brauchen Sie die explizite private Referenz und Getter/Setter? Scala macht das für dich: 'class Cell [+ T] (val t: T) {...}' –

Antwort

5

kontra Positionen für einen Typ sind (unter anderem) alle Positionen, an denen Sie eine Instanz dieses Typs an eine Methode übergeben können. Daher befinden sich alle Methodenparameter in kontravarianten Positionen. Da Sie T als kovariant (+T) deklariert haben, wird dies vom Compiler nicht zugelassen. Ihre einzigen Optionen sind:

  • make T invariant
  • modifizieren, um die Set-Methode, so dass es eine neue Instanz von Cell zurück und Cell wird damit unveränderlich.
  • die Set-Methode entfernen, auch Cell unveränderlich

Wenn der Compiler erlaubt, dass Sie eine Set-Methode haben, wie Sie es umgesetzt werden, dass die Art System unsicher machen würde, da es Ihnen zu schreiben erlauben würde:

val cs:Cell[String] = new Cell("") 
val ca:Cell[Any] = cs 
ca.set(5) 
val s:String = cs.get //boom 
+0

Sollte 'ca.set (5)' anstelle von 'cs.set (5) sein' –

+0

danke, geändert es –

4

Die kurze Antwort ist, dass Sie keinen veränderbaren Container haben können, der kovariant ist. Unter der Annahme, dies kompiliert, dann in Ihrem Beispiel könnten die letzten beiden Zeilen lesen:

val cA: Call[A] = cB 
cA.set(new A) 

Die erste Zeile erlaubt werden würde, weil ein Cell[B] ist ein Cell[A] aufgrund der Verwendung von +T. Und dann ist auch die zweite Zeile erlaubt - da kann man natürlich eine Cell[A] setzen um eine A zu halten.

Aber jetzt, cB.get gibt eine Instanz von A zurück, keine B! Dies macht keinen Sinn, und es gibt keine Möglichkeit, diesen Widerspruch zu lösen, während die Covarianz in Cell's type-Parameter noch erlaubt ist.


Für eine längere, formale/umfassende Antwort finden Sie diese Frage: Scala covariance/contravariance

Verwandte Themen