我正在使用抽象类型,并且在让Scala编译器统一两个应该相同的类型时遇到问题。这些是我的定义:
trait Chromosome {
type Gene
val size : Int
def apply(idx : Int) : Gene
def update(idx : Int, g : Gene)
def indices = Range(0, size-1)
}
trait Individual {
type Fitness
implicit protected val ord: Ordered[Fitness] = implicitly[Ordered[Fitness]]
val chromosome : Chromosome
def size : Int = chromosome.size
def apply(idx : Int) : chromosome.Gene = chromosome.apply(idx)
def update(idx : Int, g : chromosome.Gene ) = chromosome.update(idx, g)
protected var _fitness : Fitness = _
def fitness : Fitness = _fitness
def fitness_=(f : Fitness):Unit = _fitness = f
}
case class ArrayChromosome(size : Int) extends Chromosome {
implicit protected val tag : ClassTag[Gene] = implicitly[ClassTag[Gene]]
protected val xs : Array[Gene] = new Array[Gene](size)
def apply(idx : Int) = xs(idx)
def update(idx : Int, g : Gene) = xs(idx) = g
}
abstract class ArrayIndividual(size : Int) extends Individual {
val chromosome = ArrayChromosome(size)
}
class MyIndividual(size : Int) extends ArrayIndividual(size) {
type Gene = Int
type Fitness = Double
}
object Test extends App {
val i1 = new MyIndividual(10)
i1.fitness = 10.5
i1.chromosome(0) = 6
print(i1)
}
即问题出在这一行:
i1.chromosome(0) = 6
,类型错误是:
Error:(75, 22) type mismatch;
found : Int(6)
required: abstractTypes.Test.i1.chromosome.Gene
i1.chromosome(0) = 6
似乎编译器无法将i1.chromosome.Gene
与Int
统一起来。
我有两个问题:
toString
正确定义了Individual
。运行java.lang.NullPointerException
时,为什么会收到Test
。似乎该错误与Gene
ClassTag
有关,但我不确定。 响应代码至@ som-snytt:
abstract class ArrayIndividual(size : Int) extends Individual {
type Gene
implicit protected def tag2: ClassTag[Gene]
val chromosome = new ArrayChromosome(size) {
type Gene = ArrayIndividual#Gene
protected val tag : ClassTag[Gene] = tag2
}
}
class MyIndividual(size : Int) extends ArrayIndividual(size) {
type Fitness = Double
type Gene = Int
implicit protected val tag2 : ClassTag[Gene] = implicitly[ClassTag[Gene]]
override def toString = s"${super.toString} $chromosome"
}
答案 0 :(得分:1)
在Scala中,类型不是全局范围的。您已将Gene
作为Chromosome
类型的成员编写,但您尝试在Individual
的子类中定义它(其中包含“Chromosome
,而不是“是一个”Chromosome
)。
您可以选择声明和定义的位置,但它必须位于同一层次结构中,就像覆盖术语成员(如方法)时一样。
individual.Gene
与您示例中的chromosome.Gene
无关。
无论如何,将类型定义移动到ClassTag所需的位置:
case class ArrayChromosome(size : Int) extends Chromosome {
type Gene = Int
implicit protected val tag : ClassTag[Gene] = implicitly[ClassTag[Gene]]
噢,我只是注意到你是在递归地定义你的隐含。隐含在RHS上使用你所定义的隐含。所以不要这样做。编译器自己召唤隐式。
但是如果你确实需要在一个没有修复别名类型的超类中提供一个隐式标记,你可以使用一个抽象方法来提供一个可以在一个具体类中实现的类标记。
例如,让Individual
子类指定具体的Chromosome
:
abstract class ArrayChromosome(val size : Int) extends Chromosome {
//type Gene = Int
//implicit protected val tag : ClassTag[Gene] = implicitly[ClassTag[Gene]]
implicit protected def tag: ClassTag[Gene]
protected lazy val xs : Array[Gene] = new Array[Gene](size)
def apply(idx : Int) = xs(idx)
def update(idx : Int, g : Gene) = xs(idx) = g
}
abstract class ArrayIndividual(size : Int) extends Individual {
//val chromosome = ArrayChromosome(size)
val chromosome = new ArrayChromosome(size) {
type Gene = Int
protected val tag = implicitly[ClassTag[Gene]]
}
}
class MyIndividual(size : Int) extends ArrayIndividual(size) {
type Fitness = Double
override def toString = s"${super.toString} $chromosome"
}