多态Scala返回类型

时间:2013-02-06 23:43:29

标签: scala generics polymorphism return-type

我有一个抽象的Scala类Base,它有子类Derived1Derived2Base定义了一个函数f(),它返回与其实现类相同类型的对象。因此Derived1.f()会返回Derived1Derived2.f()会返回Derived2。我如何在Scala中写这个?

到目前为止,我已经提出了这个问题。

package com.github.wpm.cancan

abstract class Base {
  def f[C <: Base]: C
}

case class Derived1(x: Int) extends Base {
  def f[Derived1] = Derived1(x + 1)
}

case class Derived2(x: Int) extends Base {
  def f[Derived2] = Derived2(x + 2)
}

这会产生以下编译器错误:

type mismatch;
[error]  found   : com.github.wpm.cancan.Derived1
[error]  required: Derived1
[error]   def f[Derived1] = Derived1(x + 1)

type mismatch;
[error]  found   : com.github.wpm.cancan.Derived2
[error]  required: Derived2
[error]   def f[Derived2] = Derived2(x + 2)

此错误消息令我感到困惑,因为我认为com.github.wpm.cancan.Derived1在此上下文中应与Derived1相同。

2 个答案:

答案 0 :(得分:15)

Randall Schulz指出了当前代码不起作用的原因之一。但是,使用F-bounded polymorphism

可以得到你想要的东西
trait Base[C <: Base[C]] { def f: C }

case class Derived1(x: Int) extends Base[Derived1] {
  def f: Derived1 = Derived1(x + 1)
}

case class Derived2(x: Int) extends Base[Derived2] {
  // Note that you don't have to provide the return type here.
  def f = Derived2(x + 2)
}

基本特征上的类型参数允许您在那里讨论实现类 - 例如。在f的返回类型中。

答案 1 :(得分:8)

只是添加一个小精度(非常好)特拉维斯·布朗回答:C中的trait Base[C <: Base[C]]不是让你引用实现类;它只是坚持写subclass extends Base[subclass]的惯例,让你这样做。我不知道要提到这种类型。为了澄清我的意思,这个编译

trait Base[C <: Base[C]] { def f: C }

case class Derived1(x: Int) extends Base[Derived1] {
  def f: Derived1 = Derived1(x + 1)
}
// a Derived2 where f returns Derived1!!
case class Derived2(x: Int) extends Base[Derived1] {
  def f = Derived1(x + 2)
}

现在,如果您要将Base的实现作为案例类,那么您可以通过自我类型绑定实现此目的:

trait Base[C <: Base[C]] { self: C => 
  def f: C 
}

case class Derived1(x: Int) extends Base[Derived1] {
  def f: Derived1 = Derived1(x + 1)
}
// a Derived2 where f returns Derived1!!
// this won't compile now
case class Derived2(x: Int) extends Base[Derived1] {
  def f = Derived1(x + 2)
}