协变类型T出现在不变位置

14

我正在学习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本地协变类,会更好吗?
提前感谢!
P.S.:我也尝试过使用class和abstract class而不是trait,但结果总是相同!
编辑:在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) 
    }
}

现在我认为我可以在不同类型中放置和检索数据,并使用所有类型检查工具!

2个回答

14

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

假设你执行以下操作:

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),但这将防止用户改变内容,如果这是您的意图。您还可以在类内部拥有一个数组,只要它被声明为private [this](这也将使更改内容变得非常困难)。如果您希望客户端允许更改Gene的内容,则可能无法使Gene协变。


不需要改变它,我确实考虑过向量(Vector)。我的主要需求是让客户端代码管理不同Gene[T]的数组,但仍然具有操作的类型约束。我知道这很困难,而且由于我还处于我的第一步,可能我只是想得太过函数化或太过动态,但我打算开发更大的东西,这可能是一个要求:自动装箱和拆箱值。如果您愿意,我可以重新表述问题! - Vincenzo Maggio
请继续尝试。虽然您的方法行不通,但是由于不知道您需要什么,因此很难提供更多帮助。您是否需要使用数组来提高性能?客户端预期如何处理异构的Gene[T]集合? - Didier Dupont
我编辑了我的答案。请检查一下,因为我认为在你的帮助下我已经找到了解决方案。显然,我会接受你的答案 ;) - Vincenzo Maggio
在你的代码片段中,我认为有一个打字错误。你声明了 typed 但是没有使用它。它应该在第二行而不是 gene 对吗? - Tomas Lazaro

3

gene的类型需要在其类型参数上是协变的。为了实现这一点,您必须选择一个不可变的数据结构,例如列表(list)。但是,您可以使用scala.collection.immutable包中的任何数据结构。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接