子类和返回类型

时间:2011-03-22 06:24:45

标签: 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
}

所以,基本上,我想要的是让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
}

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

1 个答案:

答案 0 :(得分: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
}

假设我有

class FooBar extends PDF[Double] { ... }

我做了:

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

所以,我告诉编译器我希望SFooBar,但是你要返回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
}

它有点冗长,但它使PDF类型签名更清晰。