2011-03-22 113 views
1

比方说,我想有类似以下内容:子类和返回类型

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的类型系统的一些重要事实,请您在此澄清我在做什么错误,并告诉我如何仅使用一个类型参数来执行此操作?

回答

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)) 

所以,我要告诉我想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 
} 

它更详细一点,但它一直PDF类型签名清洁。

+0

谢谢!由于你的“FooBar”解释,我现在明白我做错了什么。我的主要目标是保持签名清晰,所以这正是所寻求的。 – fotNelton 2011-03-22 13:01:00