13

我正在 Scala 中迈出第一步,我想让以下代码工作:

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

编译器给出的错误是:covariant type T occurs in invariant position in type => Array[T] of value gene

我知道我可以做类似的事情:

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

但这并不能解决问题,因为我需要一个值:实际上我想说的是“我不在乎内部类型,我知道基因将具有返回其内容的基因字段”。(这里的 +T 是因为我想做类似的事情type Genome = Array[Gene[Any]],然后将其用作单个基因类的包装器,这样我就可以拥有异构数组类型)是否可以在 Scala 中做到这一点,或者我只是采取了错误的方法? 使用不同的结构会更好吗,比如 Scala 原生协变类?

提前致谢!

PS:我也尝试过使用类和抽象类而不是特征,但结果总是相同!

编辑:在 Didier Dupont 的善意建议下,我来到了这段代码:

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

所以我现在认为我可以放入和检索不同类型的数据,并将它们与所有类型检查的好东西一起使用!

4

2 回答 2

13

数组是不变的,因为您可以在其中写入。

假设你这样做

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

这会崩溃(您实例中的数组是 Array[String] 并且不会接受 Date)。这就是编译器阻止这种情况的原因。

从那里开始,这在很大程度上取决于您打算对 Gene 做什么。您可以使用协变类型而不是Array(您可能会考虑Vector),但这将阻止用户改变内容,如果这是您想要的。你也可以在类中有一个 Array,只要它是 decladed 的private [this](这也使得改变内容变得非常困难)。如果您希望允许客户端更改 Gene 的内容,则可能无法使 Gene 协变。

于 2012-07-30T13:09:00.357 回答
3

的类型gene需要在其类型参数中是协变的。为此,您必须选择不可变的数据结构,例如列表。但是您可以使用scala.collection.immutable包中的任何数据结构。

于 2012-07-30T13:08:17.427 回答