2011-08-14 116 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然后调用超级类初始化。