2013-01-11 8 views
5

Ho codice:errore con la definizione covariante e tipi controvarianti

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) 

ma ho l'errore in linea: 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 }

spiegare, si prega di

+1

Oltre alle risposte penetranti, perché avete bisogno il riferimento esplicito e privato getter/setter? Scala fa questo per te: 'classe Cella [+ T] (val t: T) {...}' –

risposta

5

posizioni controvariante per un tipo sono (tra gli altri) qualsiasi posizione che ti permetta di passare un'istanza di quel tipo a un metodo. Quindi tutti i tipi di parametri del metodo sono in posizioni controvarianti. Dal momento che hai dichiarato T come covariante (+T), il compilatore non lo consentirà. Le uniche opzioni sono:

  • make T invariante
  • modificare il metodo impostato in modo che restituisce una nuova istanza di Cell e Cell diventa così immutabile.
  • rimuovere il metodo set, anche facendo Cell immutabile

Se il compilatore ha permesso di avere un metodo set, come si implementato, che renderebbe il sistema di tipo pericoloso, in quanto permetterebbe di scrivere:

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

Dovrebbe essere 'ca.set (5)' invece di 'cs.set (5)' –

+0

grazie, cambiato esso –

4

La risposta breve è che non è possibile avere un contenitore mutabile che sia covariante. Assumendo questo compilato, quindi nel tuo esempio, le ultime due righe potrebbe leggere:

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

La prima linea sarebbe consentito, perché un Cell[B]è un Cell[A] a causa dell'uso di +T. E poi è consentita anche la seconda riga, perché ovviamente è possibile impostare uno Cell[A] per contenere uno A.

Ma ora, cB.get restituisce un'istanza di A, non un B! Questo non ha alcun senso e non c'è modo di risolvere questa contraddizione pur consentendo la covarianza nel parametro di tipo di cella.


Per una risposta più lunga, più formale/completo, vedere questa domanda: Scala covariance/contravariance

Problemi correlati