2012-07-30 23 views
6

Estoy moviendo mis primeros pasos en la Scala y me gustaría hacer el siguiente código funciona:tipo covariante T se produce en la posición invariable

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

El error que el compilador da es: covariant type T occurs in invariant position in type => Array[T] of value gene

sé que podría hacer algo como:

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

pero esto no resuelve el problema porque necesito un valor: practicamente lo que estoy tratando de decir es "no me importa de los complementos tipo ide, sé que los genes tendrán un campo genético que devolverá su contenido ". (el + T aquí es porque quiero hacer algo como type Genome = Array[Gene[Any]] y luego lo uso como un contenedor contra las clases de genes individuales, así que puedo tener un tipo de matriz heterogénea) ¿Es posible hacerlo en Scala o simplemente estoy tomando un enfoque equivocado? ¿Sería mejor utilizar una estructura diferente, como una clase covariante nativa de Scala?

¡Gracias de antemano!

P.S .: ¡También he intentado con clase y clase abstracta en lugar de rasgo, pero siempre con los mismos resultados!

EDIT: con la sugerencia tipo de Didier Dupont Me vino a este código:

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) 
    } 
} 

Así que ahora creo que pueda poner y recuperar datos de diferentes tipos y utilizarlos con todo tipo revisando golosinas!

Respuesta

9

La matriz es invariable porque puede escribir en ella.

Supongamos que haces

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

esto se estrellaría (la matriz en su instancia es un conjunto [String] y no aceptará una fecha). Por eso el compilador evita eso.

A partir de ahí, depende en gran medida de lo que pretenda hacer con Gene. Puede usar un tipo de covariante en lugar de Array (puede considerar Vector), pero eso evitará que el usuario mute el contenido, si esto fue lo que pretendía. También puede tener una matriz dentro de la clase, siempre que se declare private [this] (lo que hará que sea bastante difícil mutar el contenido también). Si desea que se le permita al cliente mutar el contenido de un gen, probablemente no será posible hacer que Gene sea covariante.

+0

No, no necesito mutarlo y de hecho pensé en Vector. Mi principal requisito es tener el código del cliente administrando una matriz de diferentes Gene [T], pero aún con restricciones de tipo en las operaciones. Sé que es difícil y al estar todavía en mis primeros pasos tal vez simplemente esté pensando demasiado funcional o demasiado dinámico, pero tengo la intención de desarrollar algo más grande y esto podría ser un requisito: boxeo automático y unboxing de valores. Si quieres puedo reformular la pregunta! –

+0

Por favor hazlo. Lo que hagas no funcionará, pero al no saber lo que necesitas, es difícil ayudar más. ¿El rendimiento es la razón por la que quieres una matriz?¿Qué se espera que el cliente haga con una colección heterogénea de Gene [T]? –

+0

Editado mi respuesta. Por favor, revísela porque creo que gracias a su ayuda encontré una solución. Obviamente voy a aceptar tu respuesta;) –

2

El tipo de gene debe ser covariante en su parámetro de tipo. Para que eso sea posible, debe elegir una estructura de datos inmutables, por ejemplo, una lista. Pero puede usar cualquier estructura de datos del paquete scala.collection.immutable.

Cuestiones relacionadas