我在尝试编写一个函数时遇到类型不匹配的问题,该函数将扩展抽象类的对象作为输入(和输出)。
这是我的抽象类:
abstract class Agent {
type geneType
var genome: Array[geneType]
}
这是我的功能:
def slice[T <: Agent](parentA: T, parentB: T):(T, T) = {
val genomeSize = parentA.genome.length
// Initialize children as identical to parents at first.
val childA = parentA
val childB = parentB
// the value 'index' is sampled randomly between 0 and
// the length of the genome, less 1.
// This code omitted for simplicity.
val index;
val pAslice1 = parentA.genome.slice(0, index + 1)
val pBslice1 = parentB.genome.slice(index + 1, genomeSize)
val genomeA = Array.concat(pAslice1, pBslice1)
childA.genome = genomeA
// And similary for childB.
// ...
// ...
return (childA, childB)
}
我收到错误(顺便说一下,我用sbt运行),如下所示:
[error] .......... type mismatch;
[error] found : Array[parentA.geneType]
[error] required: Array[T#geneType]
我不确定问题是什么,因为我是抽象类,泛型类型参数化的新手,也可能是我不知道的其他相关概念。
答案 0 :(得分:2)
在你的构造中,parentA
和parentB
很可能是不同的类型,T
只给你一个上限(它们必须至少与T一样具体) )。数组在元素类型中是不变的,因此你不能在这里以合理的方式交换元素。
您的代码的第二个问题是您返回T
类型的对象,但实际上您正在改变输入参数。你想要变异,然后声明方法的返回类型Unit
以使其清晰;或者创建T
的新实例并使Agent
成为不可变的。这取决于你的性能要求,但我总是首先尝试不可变的变体,因为它更容易推理。
这是可变的变体。请注意,因为数组是JVM上的特殊对象(没有发生类型擦除),所以你需要为它们提供所谓的类标记:
abstract class Agent {
type geneType
var genome: Array[geneType]
implicit def geneTag: reflect.ClassTag[geneType]
}
def slice[A](parentA: Agent { type geneType = A },
parentB: Agent { type geneType = A }): Unit = {
val genomeSize = parentA.genome.length
require (parentB.genome.length == genomeSize)
import parentA.geneTag
val index = (math.random * genomeSize + 0.5).toInt
val (aInit, aTail) = parentA.genome.splitAt(index)
val (bInit, bTail) = parentB.genome.splitAt(index)
val genomeA = Array.concat(aInit, bTail)
val genomeB = Array.concat(bInit, aTail)
parentA.genome = genomeA
parentB.genome = genomeB
}
在此,您需要parentA
和parentB
分享一个确切定义的基因类型A
。您可以定义类型别名以简化指定类型:
type AgentT[A] = Agent { type geneType = A }
def slice[A](parentA: AgentT[A], parentB: AgentT[A]): Unit = ...
要保留父项并创建新子项,最简单的方法是将复制方法添加到Agent
类:
abstract class Agent {
type geneType
var genome: Array[geneType]
implicit def geneTag: reflect.ClassTag[geneType]
def copy(newGenome: Array[geneType]): AgentT[geneType]
}
type AgentT[A] = Agent { type geneType = A }
def slice[A](parentA: AgentT[A], parentB: AgentT[A]): (AgentT[A], AgentT[A]) = {
val genomeSize = parentA.genome.length
require (parentB.genome.length == genomeSize)
import parentA.geneTag
val index = (math.random * genomeSize + 0.5).toInt
val (aInit, aTail) = parentA.genome.splitAt(index)
val (bInit, bTail) = parentB.genome.splitAt(index)
val genomeA = Array.concat(aInit, bTail)
val genomeB = Array.concat(bInit, aTail)
(parentA.copy(genomeA), parentB.copy(genomeB))
}
如果您不需要压缩性能的最后几位,则可以使用Vector
而不是Array
等不可变集合。
case class Agent[A](genome: Vector[A]) {
def size = genome.size
}
def slice[A](parentA: Agent[A], parentB: Agent[A]): (Agent[A], Agent[A]) = {
val genomeSize = parentA.size
require (parentB.size == genomeSize)
val index = (math.random * genomeSize + 0.5).toInt
val (aInit, aTail) = parentA.genome.splitAt(index)
val (bInit, bTail) = parentB.genome.splitAt(index)
val genomeA = aInit ++ bTail
val genomeB = bInit ++ aTail
(parentA.copy(genomeA), parentB.copy(genomeB))
}