2011-08-14 118 views
4

初始化我定義具有抽象類型的類如下:問題抽象類的類型Scala中

abstract class AbsCell2{ 
    type T 
    val init: T 
    private var value: T = { 
     println("Hello "+init); 
     init 
    } 
    def get : T = value 
    def set(x : T) = { value = x} 
} 

現在我實例化一個對象int型的

scala> val cell = new AbsCell2{type T = Int ; val init = 10} 
Hello 0 
cell: AbsCell2{type T = Int} = [email protected] 

注重輸出從println。它接縫該變量init尚未被初始化爲10.注意,斯卡拉的版本是2.9.0-1

+0

本示例借用Martin Ordersky提供的演示文稿。 http://lampwww.epfl.ch/~odersky/ –

+1

但是現在在REPL中執行'cell.init',它會_will_向您顯示10.您的問題是爲什麼在對象初始化之前它不打印10? –

+0

我想愛國者也在問爲什麼'細胞。get'返回0,以及如何讓它返回10. –

回答

4

我認爲你正在尋找Scala的early initializers

scala> val cell = new {type T = Int ; val init = 10} with AbsCell2 
Hello 10 
cell: AbsCell2{val init: Int; type T = Int} = [email protected] 

scala> cell.get 
res0: cell.T = 10 

早期初始化允許你分配一個新的對象並設置一些特定的字段之前該類的構造函數運行。在這種情況下,由於value取決於init,我們使用早期初始化語法(new { val init = ... } with AbsCell2)首先設置init,以便類構造函數可以正確初始化value

也看到這個問題:從VAL In Scala, what is an "early initializer"?

+0

不好意思,什麼是「早期初始化程序」的語法? –

+0

對不起,新{type T = Int; val init = 10}用AbsCell2和新的AbsCell2 {type T = Int; val init = 10} –

+0

我更詳細地更新了答案。 –

0

更改爲DEF:

abstract class AbsCell2{ 
    type T 
    def init: T 
    private var value: T = { 
    println("Hello "+init); 
    init 
    } 
    def get : T = value 
    def set(x : T) = { value = x} 
} 

它按預期工作:

scala> val cell = new AbsCell2{type T = Int ; def init = 10} 
Hello 10 
cell: AbsCell2{type T = Int} = [email protected] 
0

有關與AbsCell2和new AbsCell2 { type T = Int ; val init = 10 }new { type T = Int ; val init = 10 }之間的差異問題。

第一個是所謂的早期初始化或預先初始化的字段(在Programming Scala中的抽象成員一章中提到過)。它允許子類在超類被調用之前初始化字段 在這種情況下,init有。已經AbsCell2的初始化之前被設定爲10

後者是正常的繼承,它會創建一個匿名類,然後擴展AbsCell2,就像:

class AbsCell' extends AbsCell { 
    type T = Int 
    val init = 10 
} 

然而,匿名類被後初始化抽象類AbsCell2,所以init在其本身的初始化中不可用,即init是Type的默認值,在這種情況下爲0。因此,您在打印得0

使用scalac -Xprint:all Test.scala,你會看到以下內容:。

abstract class AbsCell2 extends Object { 
    <stable> <accessor> def init(): Object; 
    .... 
    def <init>(): AbsCell2 = { 
    AbsCell2.super.<init>(); 
    AbsCell2.this.value = { 
     scala.this.Predef.println("Hello ".+(AbsCell2.this.init())); 
     AbsCell2.this.init() 
    }; 
    () 
    } 
}; 

// normal initialization 
final class anon$1 extends AbsCell2 { 
    private[this] val init: Int = _; 
    <stable> <accessor> def init(): Int = anon$1.this.init; 
    .... 
    def <init>(): <$anon: AbsCell2> = { 
    anon$1.super.<init>(); 
    anon$1.this.init = 10; 
    () 
    } 
}; 

// early initialization 
final class anon$2 extends AbsCell2 { 
    private[this] val init: Int = _; 
    <stable> <accessor> def init(): Int = anon$2.this.init; 
    .... 
    def <init>(): <$anon: AbsCell2> = { 
    val init: Int = 10; 
    anon$2.this.init = init; 
    anon$2.super.<init>(); 
    () 
    } 
} 

從代碼中,我們可以看到,對於正常的初始化,初始化時的初始化後設置爲3超類AbsCell2,當AbsCell2.this.init()被調用時,它實際上是指子類的init字段,而3還沒有設置,所以我們得到默認的類型值。相反,早期初始化首先將init設置爲3然後調用超級類初始化。