子类和返回类型

fot*_*ton 1 scala covariance subtype

假设我想要有以下内容:

abstract class PDF[T, S <: PDF[T, _]] {
  def fit(obs: Seq[T], weights: Seq[Double]): S
}

class PDFGaussian(val mu: Double, val Sigma: Double) extends PDF[Double, PDFGaussian] {
  def fit(obs: Seq[Double], weights: Seq[Double]): PDFGaussian =
    new PDFGaussian(...) // bla bla bla
}
Run Code Online (Sandbox Code Playgroud)

所以,基本上,我想要的是让fit函数返回其封闭类的类型的实例,显然必须是它的子类PDF[T].但是,不必使用双参数化,PDF[T, S <: PDF[T, _]]我宁愿只使用一个类型参数,如下所示:

abstract class PDF[T] {
  def fit[S <: PDF[T]](obs: Seq[T], weights: Seq[Double]): S
}

class PDFGaussian(val mu: Double, val Sigma: Double) extends PDF[Double] {
  def fit[S <: PDF[_]](obs: Seq[Double], weights: Seq[Double]): S =
    new PDFGaussian(...) // bla bla bla
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我这样做,编译器会因为返回PDFGaussian而对我大喊大叫而不是S.既然我明显错过了关于scala类型系统的一些重要事实,请你澄清一下我做错了什么,并告诉我如何用一个类型参数做到这一点?

Dan*_*ral 5

你的第一个解决方案非常好,恕我直言.但是让我们谈谈这些问题.首先,关于这里有什么问题:

abstract class PDF[T] {
  def fit[S <: PDF[T]](obs: Seq[T], weights: Seq[Double]): S
}

class PDFGaussian(val mu: Double, val Sigma: Double) extends PDF[Double] {
  def fit[S <: PDF[_]](obs: Seq[Double], weights: Seq[Double]): S =
    new PDFGaussian(...) // bla bla bla
}
Run Code Online (Sandbox Code Playgroud)

让我说我有

class FooBar extends PDF[Double] { ... }
Run Code Online (Sandbox Code Playgroud)

我这样做:

val pdfg = new PDFGaussian(1.0, -1.0)
val foobar = pdfg.fit[FooBar](List(0.5, 0.75), List(4, 2))
Run Code Online (Sandbox Code Playgroud)

所以,我告诉编译器我想S成为FooBar,但你回来了PDFGaussian!这就是编译器所抱怨的.

那么,如何解决呢?嗯......很难.:-) 这个怎么样:

abstract class PDF[T] {
  type S <: PDF[T]
  def fit(obs: Seq[T], weights: Seq[Double]): S
}

class PDFGaussian(val mu: Double, val Sigma: Double) extends PDF[Double] {
  type S = PDFGaussian
  def fit(obs: Seq[Double], weights: Seq[Double]): S =
    new PDFGaussian(...) // bla bla bla
}
Run Code Online (Sandbox Code Playgroud)

它有点冗长,但它保持了PDF类型签名更清晰.