Scala 为抽象类的扩展定义函数
我在尝试编写一个函数时遇到了类型不匹配的问题,该函数将扩展抽象类的对象作为输入(和输出) 这是我的抽象类:Scala 为抽象类的扩展定义函数,scala,abstract-class,type-parameter,Scala,Abstract Class,Type Parameter,我在尝试编写一个函数时遇到了类型不匹配的问题,该函数将扩展抽象类的对象作为输入(和输出) 这是我的抽象类: abstract class Agent { type geneType var genome: Array[geneType] } 以下是我的功能: def slice[T <: Agent](parentA: T, parentB: T):(T, T) = { val genomeSize = parentA.genome.length // Initiali
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)
}
我不确定问题出在哪里,因为我不熟悉抽象类、泛型类型参数化,可能还不知道其他相关概念的名称 在你的结构中,
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 = ...
要保留父对象并创建新的子对象,最简单的方法是将copy方法添加到
代理
类:
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))
}
需要注意的一点是,在这里执行
parentA.genome.slice(0,index+1)
时,返回类型是Array[parentA.type#geneType]
,而您只希望返回Array[geneType]
。但是我不知道为什么,可能是t
一个抽象类的子类型使得类型绑定到类实例。谢谢,伙计。我想我已经得到了您建议的不变解决方案(仍然使用数组)。我该如何部分应用这个函数?你说的“部分应用”是什么意思?我的意思是得到一个“部分应用的函数”文本,就像你写的那样:val slicer=slice(u,u)。再加上类型参数,例如,slice[Int]
还有一个问题。我选择了你建议的第二种方法。如果将抽象类定义和“slice”函数的定义放在不同的文件中,那么定义类型别名的最合适位置是哪里?如果在抽象类中定义类型,则会出现找不到该类型的错误。如何将此类型别名导入定义切片函数的文件中?
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))
}