在 Scala 中绑定引用自身的类型意味着什么?

obe*_*tie 2 generics scala f-bounded-polymorphism

我在 GitHub 上查看一些代码,发现了这个类型声明:

abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product with TreePatternBits {
Run Code Online (Sandbox Code Playgroud)

(这是来自 Spark 源代码,尽管这个问题实际上并不是关于 Spark,而是关于 Scala 的类型系统。)

这对我来说是新的。用简单的英语来说,这种类型绑定是什么意思?

Mat*_*zok 9

几乎没有人阅读关于 System F 的白皮书(评论中提到),人们仍然直观地使用 F 绑定型多态性。

您需要了解的是,类/特征MyType[A <: MyType[A]]强制您将其扩展为class Impl extends MyType[Impl],即将其自身作为类型参数传递。

trait Interface[A <: Interface[A]] {

  def getValue: String

  def setValue(value: String): A
}
Run Code Online (Sandbox Code Playgroud)

如果您想做类似的事情,这很有用:

class Impl(value: String) extends Interface[Impl] {

  override def getValue: String = value

  override def setValue(value: String): Impl = new Impl(value)
}
Run Code Online (Sandbox Code Playgroud)

如果没有这个A <: Interface[A]( typeA是 /extends 的子类型Impl[A]),有人可能会实现:

// no F-bound type polymorphism
trait Interface[A] {

  def getValue: String

  def setValue(value: String): A
}

class Foo

class Impl extends Inteface[Foo] {

  override def getValue: String = value

  // we wanted to force implementation to have Impl here but now we cannot
  override def setValue(value: String): Foo = new Foo
}
Run Code Online (Sandbox Code Playgroud)

如果您有对一些代数进行建模的接口,例如:

trait Number[A <: Number[A]] {

  def add(a: A): A
}
Run Code Online (Sandbox Code Playgroud)

使实现方法的输入/输出与其自身类型相同:

class Integer(val i: Int) extends Number[Integer] {

  def add(a: Integer): Integer = new Integer(i + a.i)
}
Run Code Online (Sandbox Code Playgroud)

它在 OOP 中更受欢迎,因为 FP 提供了使用类型类的替代方法。