2011-03-22 118 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