2012-07-30 8 views
6

mi sto muovendo i primi passi in Scala e vorrei fare la seguente codice funziona:covariante tipo T si verifica in posizione invariante

trait Gene[+T] { 
    val gene: Array[T] 
} 

L'errore che il compilatore dà è: covariant type T occurs in invariant position in type => Array[T] of value gene

so che potrei fare qualcosa di simile:

trait Gene[+T] { 
    def gene[U >: T]: Array[U] 
} 

, ma questo non risolve il problema perché ho bisogno di un valore: praticamente quello che sto cercando di dire è "non mi importa delle ins tipo ide, so che i geni avranno un campo genico che restituisce il suo contenuto ". (il + T è perché voglio fare qualcosa come type Genome = Array[Gene[Any]] e quindi usarlo come un wrapper contro le classi del gene singolo in modo da poter avere un tipo di array eterogeneo) È possibile farlo in Scala o sto semplicemente prendendo un approccio sbagliato? Sarebbe meglio usare una struttura diversa, come una classe covariante nativa di Scala?

Grazie in anticipo!

P.S .: Ho anche provato con classe e classe astratta invece che tratto ma sempre gli stessi risultati!

EDIT: con il genere suggerimento di Didier Dupont Sono venuto a questo codice:

package object ga { 


    class Gene[+T](val gene: Vector[T]){ 

    def apply(idx: Int) = gene(idx) 

    override def toString() = gene.toString 

    } 

    implicit def toGene[T](a: Vector[T]) = new Gene(a) 

    type Genome = Array[Gene[Any]] 

} 

package test 

import ga._ 

object Test { 
    def main(args: Array[String]) { 
     val g = Vector(1, 3, 4) 

     val g2 = Vector("a", "b") 

     val genome1: Genome = Array(g, g2) 

     println("Genome") 

     for(gene <- genome1) println(gene.gene) 
    } 
} 

Così ora penso posso mettere e recuperare i dati in diversi tipi e usarli con tutti i tipi controllando le chicche!

risposta

9

L'array è invariante perché è possibile scrivere in esso.

Supponiamo che fai

val typed = new Gene[String] 
val untyped : Gene[Any] = typed // covariance would allow that 
untyped.gene(0) = new Date(...) 

questo potrebbe andare in crash (la matrice nella vostra istanza è un array [String] e non accetterà una data). Ecco perché il compilatore lo impedisce.

Da lì, dipende molto da cosa intendete fare con Gene. È possibile utilizzare un tipo covariante anziché Array (è possibile considerare Vector), ma ciò impedirà all'utente di modificare il contenuto, se questo era ciò che si intendeva. Potresti anche avere una matrice all'interno della classe, a condizione che sia stata creata con lo private [this] (che renderà molto difficile anche la modifica del contenuto). Se si desidera consentire al client di mutare il contenuto di un gene, probabilmente non sarà possibile rendere Gene covariante.

+0

No, non ho bisogno di modificarlo e, in effetti, penso a Vector. Il mio requisito principale è avere il codice client che gestisca una matrice di Gene [T] diversa, ma ancora con vincoli di tipo sulle operazioni. So che è difficile e, essendo ancora ai miei primi passi, forse penso semplicemente troppo funzionale, o troppo dinamico, ma ho intenzione di sviluppare qualcosa di più grande e questo potrebbe essere un requisito: il pugilato automatico e l'unboxing dei valori. Se vuoi posso riformulare la domanda! –

+0

Si prega di fare. Quello che fai non funzionerà, ma non sapendo di cosa hai bisogno, è difficile aiutare di più. La performance è la ragione per cui vuoi una matrice?Cosa dovrebbe fare il cliente con una collezione eterogenea di Gene [T]? –

+0

Modificato la mia risposta. Si prega di rivederlo perché penso che grazie al vostro aiuto ho trovato una soluzione. Ovviamente accetterò la tua risposta;) –

2

Il tipo di gene deve essere covariante nel suo parametro tipo. Affinché ciò sia possibile, devi scegliere una struttura dati immutabile, per esempio lista. Ma è possibile utilizzare qualsiasi struttura dati dal pacchetto scala.collection.immutable.

Problemi correlati