如何在继承的特征中定义的方法中强制执行子类型?我在???中放置了什么?下面

trait Organism {
 def reproduce(org:???):Bool
}

class Amoeba extends Organism {
  def reproduce(org:Amoeba) = {// so cute..}

}
class Dinosaur extends Organism {
 def reproduce(org:Dinosaur) = { // so scary}
}


我的客户代码将类似于:

object BoozeParty {
 def gonuts() = {
    val (maleOrganism:Organism,femaleOrganism:Organism) = getOrganisms()

    maleOrganism.reproduce(femaleOrganism)

 }
}


不管我通过getOrganisms()方法发送恐龙还是变形虫,上面的代码都应该起作用,因为它返回了(Organism,Organism)的元组

我要实现的两个概念是:


变形虫知道如何与变形虫交配,而恐龙知道如何交配
与恐龙。因此,让他们找出复杂的细节。
恐龙不应传递给变形虫。只有变形虫到变形虫

最佳答案

通常使用一种称为F界多态性的方法(请参见Scala School)。

trait Organism[Self <: Organism[Self]] { self: Self =>
  def reproduceWith(org:Self):Boolean
}

class Amoeba extends Organism[Amoeba] {
  def reproduceWith(org:Amoeba) = ???
}

class Dinosaur extends Organism[Dinosaur] {
  def reproduceWith(org:Dinosaur) = ???
}

class Monster extends Dinosaur


Organism[X]其中,X声明它必须为Organism[X]。这意味着只能传入X,该Organism[X]也会扩展Dinosaur extends Organism[Amoeba]

为了防止self: Self =>我添加了一个自类型mate,该类型告诉编译器应将此特征与传入的类型混合使用。

函数现在如下所示:

def mate[Species <: Organism[Species]](male:Species, female:Species) =
  male reproduceWith female


用法是这样的:

val a1 = new Amoeba
val a2 = new Amoeba

val d1 = new Dinosaur
val d2 = new Monster

mate(a1, a2)
mate(d1, d2)
// wont compile
// mate(a1, d1)


如果要对类型(以及更复杂的代码)施加更多限制,可以查看以下答案:Scala: implementing method with return type of concrete instance

07-26 06:26