如何指定抽象方法的返回类型是子类的类型

时间:2014-05-11 12:25:44

标签: scala

在抽象类中,我如何指定方法的返回值与它所属的具体类具有相同的类型?

例如:

abstract class Genotype {
  def makeRandom(): Genotype  // must return subclass type
  def mutate(): Genotype      // must return subclass type
}

我想说,无论何时在具体的基因型类上调用mutate(),您都要确保返回同一基因型类的另一个实例。

我不希望以Genotype[SpecificGenotype259]的方式使用类型参数,因为该类型参数可能会在整个代码中激增(同样,它是多余的和令人困惑的)。我倾向于通过扩展各种特征来定义具体的基因型类。

4 个答案:

答案 0 :(得分:5)

您需要F-bounded polymorphism

abstract class Genotype[T <: Genotype[T]] {
  def makeRandom(): T  
  def mutate(): T      
}

class ConcreteGenotype extends Genotype[ConcreteGenotype] {
  def makeRandom(): ConcreteGenotype = ???
  def mutate(): ConcreteGenotype = ???
}

答案 1 :(得分:3)

abstract class Genotype {
  type T <: Genotype
  def makeRandom(): T  
  def mutate(): T      
}

这是你想要的吗?

答案 2 :(得分:1)

我建议针对这种情况使用参数化模块:

trait GenotypeSystem {
  type Genotype <: GenotypeLike

  trait GenotypeLike {
    def makeRandom(): Genotype
    def mutate(): Genotype
  }
}

// Example implementation
object IntGenotypeSystem extends GenotypeSystem {
  case class Genotype(x: Int) extends GenotypeLike {
    def makeRandom() = copy(x = Random.nextInt(10))
    def mutate(): Genotype = copy(x = x + Random.nextInt(3) - 1)
  }
}

// Example abstract usage
def replicate(gs: GenotypeSystem)(g: gs.Genotype, n: Int): Seq[gs.Genotype] =
  Seq.fill(n)(g.mutate())

这种方法很容易适应未来的修改和扩展,例如向GenotypeSystem添加其他类型。

答案 3 :(得分:0)

使用协变返回类型可能适用于您的情况吗?

abstract class Genotype {
  def makeRandom(): Genotype  // must return subclass type
  def mutate(): Genotype      // must return subclass type
}

class ConcreteGenotype(val a : Int) extends Genotype {
  override def makeRandom(): ConcreteGenotype = new ConcreteGenotype(a + 1)
  override def mutate(): ConcreteGenotype = new ConcreteGenotype(a + 2)
}

def useAbstractGenotype(g : Genotype) = g.mutate

val cg = new ConcreteGenotype(0) // cg: ConcreteGenotype = ConcreteGenotype@6c1c19c6
cg.mutate                        // res2: ConcreteGenotype = ConcreteGenotype@3fc1058a
useAbstractGenotype(cg)          // res3: Genotype = ConcreteGenotype@13515ded