2013-07-11 15 views
3

當我讀到Liftweb的源代碼,我發現了一些特質聲明:什麼`特質而ValueHolder {類型值類型}`和`特質而ValueHolder [T]之間的差異{}`

trait ValueHolder { 
    type ValueType 
    def get: ValueType 
} 

trait PValueHolder[T] extends ValueHolder { 
    type ValueType = T 
} 

我的問題是,對於以下兩個特質的聲明:

trait ValueHolder { 
    type ValueType 
} 

trait ValueHolder[T] { 
} 

我認爲它們是相等的,但它們之間是否有區別?一個人可以做或提供另一個人不能做的事嗎?

回答

6

第一個被稱爲abstract type member,第二個與Java泛型非常類似,但並不完全相同。這是實現相同目標的兩種不同方式。正如馬丁Odersky的解釋是his採訪中,一個原因既有抽象類型成員和泛型參數是正交:

一直存在着抽象的兩個概念:參數 和抽象成員。在Java中,你也有兩種方法,但它取決於你抽象的 。在Java中你有抽象方法,但是你不能把一個方法作爲一個參數傳遞給 。您沒有摘要 字段,但可以將值作爲參數傳遞。類似地,您的 不具有抽象類型成員,但可以將類型指定爲 參數。所以在Java中你也有這三種,但是有什麼抽象原則可以用於什麼類型的事情有一個 的區別。你可以爭辯說,這種區別是相當的 任意。

我們在Scala中所做的嘗試是更加完整和正交的。我們 決定成員的所有三種 具有相同的建設原則。因此,您可以擁有抽象字段以及值 參數。您可以傳遞方法(或「函數」)作爲參數,或者您可以通過它們抽象。你可以指定類型作爲參數,或者你可以通過它們抽象。我們在概念上得到的是我們 可以用另一個來建模。至少原則上,我們可以將每種參數化形式表示爲面向對象的抽象形式 。所以從某種意義上說,你可以說斯卡拉是一個更正交的 和完整的語言。

他還介紹了抽象類型成員和泛型參數之間的差異,可以在實踐中顯示出來:

但在實踐中,當您使用類型參數與許多 不同的東西,它會導致一個參數的爆炸,並且通常, 更多,在參數的範圍內。在1998 ECOOP上,Kim Bruce, Phil Wadler和我有一篇論文,我們發現當你增加 你不知道的東西的數量時,典型的程序將按照二次方式增長 。所以有很好的理由不去做參數, 但有這些抽象成員,因爲他們不會給你這個二次炸彈。

我認爲,一個偉大而簡單的例子是given比爾Veners(ScalaTest的創建者):

// Type parameter version 
trait FixtureSuite[F] { 
    // ... 
} 

// Type member version 
trait FixtureSuite { 
    type F 
    // ... 
} 

在這兩種情況下,F將是類型將夾具參數傳遞給測試,該套件子類將使具體。這是一個需要傳遞到每個測試一個StringBuilder,使用類型參數的方法測試的具體套件的一個例子:

// Type parameter version 
class MySuite extends FixtureSuite[StringBuilder] { 
    // ... 
} 

這裏是一個需要使用傳遞到每個測試一個StringBuilder測試的具體套件的例子抽象類型成員的做法:

// Type member version 
class MySuite extends FixtureSuite { 
    type F = StringBuilder 
    // ... 
} 

例如,如果你想三個不同的固定物體傳遞到測試,你就可以這樣做,但你需要指定三種類型,每一個參數。因此,類型參數的方法是choosen,你的套件類可以結束這樣看:

// Type parameter version 
class MySuite extends FixtureSuite3[StringBuilder, ListBuffer, Stack] with MyHandyFixture { 
    // ... 
} 

而與類型成員的做法,將是這樣的:

// Type member version 
class MySuite extends FixtureSuite3 with MyHandyFixture { 
    // ... 
} 

因此,顯示兩種方法以實現偉大的模塊化抽象爲目標。有關此主題的更多信息,請參閱this關於可伸縮組件的傳奇論文