Trait允许方法签名中的子类型

时间:2013-04-17 19:20:05

标签: scala generics types

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

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()方法发送恐龙或变形虫,因为它返回(有机体,有机体)的元组

我想要实现的两个概念是:

  • Amoeba知道如何与Amoeba交配,恐龙知道如何交配 与恐龙。所以让他们弄清楚错综复杂的细节。
  • 恐龙不应该传给变形虫。只有阿米巴变形虫变形虫

1 个答案:

答案 0 :(得分:8)

通常使用称为F-bounded多态的东西(参见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