多态Scala返回类型

W.P*_*ill 8 generics polymorphism scala return-type

我有一个抽象的Scala类Base,它有子类Derived1Derived2.Base定义一个函数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)
}
Run Code Online (Sandbox Code Playgroud)

这给出了以下编译器错误:

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)
Run Code Online (Sandbox Code Playgroud)

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

Tra*_*own 15

Randall Schulz指出了当前代码不起作用的原因之一.但是,使用F -bounded多态性可以得到你想要的东西:

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)
}
Run Code Online (Sandbox Code Playgroud)

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

  • 值得指出的是,F-bounded多态的这个特定实例相对众所周知的是奇怪的递归模板/类型模式,用于定义基类型中的函数,其返回值在各个地方的子类型上是多态的 - 例如,Enum的Java定义是类Enum <E extends Enum <E >>. (5认同)
  • @Impredicative:我一直听到它被称为奇怪_Recurring_模板模式,这是一个更多元. (2认同)

Edu*_*bes 8

只是为了增加一个小的精度(非常好)特拉维斯·布朗回答:这不是Ctrait 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)
}
Run Code Online (Sandbox Code Playgroud)

现在,如果你将要实现的Base是case类的实现,你可以通过自我类型绑定来实现:

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)
}
Run Code Online (Sandbox Code Playgroud)