关于scala中抽象类类初始化的问题

时间:2011-08-14 07:33:29

标签: scala types abstract

我定义了一个抽象类型的类,如下所示:

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} = $anon$1@969ebb

注意println的输出。它接缝变量init尚未初始化为10.请注意,scala的版本是2.9.0-1

3 个答案:

答案 0 :(得分: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} = $anon$1@1efa9557

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

早期初始化程序允许您在类构造函数运行之前分配新对象并设置一些特定字段。在这种情况下,由于value取决于init,我们使用早期初始化程序语法(new { val init = ... } with AbsCell2)来首先设置init,以便类构造函数可以正确初始化{{1} }}

另请参阅此问题:In Scala, what is an "early initializer"?

答案 1 :(得分:0)

从val更改为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} = $anon$1@4302df5

答案 2 :(得分:0)

有关new { type T = Int ; val init = 10 }与AbsCell2和new AbsCell2 { type T = Int ; val init = 10 }之间差异的问题。

第一个是所谓的早期初始化器或预初始化字段(在Scala编程中的摘要成员章节中提到)。它允许子类在调用超类之前初始化字段。 在这种情况下,在初始化AbsCell2之前,init已经被设置为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>();
     ()
   }
 }

从代码中我们可以看到,对于正常初始化,在超类AbsCell2初始化之后将init设置为3,当调用AbsCell2.this.init()时,它实际上引用了子类&#39; init字段和3尚未设置,所以我们得到默认的类型值。相反,早期初始化首先将init设置为3然后调用超类初始化。