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

发布于 2024-11-29 18:14:04 字数 506 浏览 0 评论 0原文

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

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

I define a class with abstract type as follow:

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}
}

Now I instantiate an object with type Int

scala> val cell = new AbsCell2{type T = Int ; val init = 10}
Hello 0
cell: AbsCell2{type T = Int} = $anon$1@969ebb

Pay attention to the output from println. It seams the variable init hasn't been initialized as 10. Note that the version of scala is 2.9.0-1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

鯉魚旗 2024-12-06 18:14:04

我认为您正在寻找 Scala 的 早期初始化器

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,以便类构造函数可以正确初始化value

另请参阅这个问题:在 Scala 中,什么是“早期初始化器”?

I think you're looking for Scala's 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

Early initializers allow you to allocate a new object and set some specific fields before the class constructor runs. In this case, since value depends on init, we use the early initializer syntax (new { val init = ... } with AbsCell2) to first set init so that the class constructor can properly initialize value.

See also this question: In Scala, what is an "early initializer"?

秋叶绚丽 2024-12-06 18:14:04

从 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

Change from val to 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}
}

It works as expected:

scala> val cell = new AbsCell2{type T = Int ; def init = 10}
Hello 10
cell: AbsCell2{type T = Int} = $anon$1@4302df5
澜川若宁 2024-12-06 18:14:04

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

第一个是所谓的早期初始化器或预初始化字段(在《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>();
     ()
   }
 }

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

For question about difference between new { type T = Int ; val init = 10 } with AbsCell2 and new AbsCell2 { type T = Int ; val init = 10 }

The first one is the so-called early-initializers or pre-initialized fields(mentioned in Abstract Members chapter in Programming In Scala)。It allows the subclass to initialize fields before the super class is called。
In this case, init has already been set as 10 before the initialization of AbsCell2。

The latter one is normal inheritance, it creates an anonymous class then extends AbsCell2, just like:

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

However, the anonymous class gets initialized after the abstract class AbsCell2, so init are not available in the initialization of itself, namely, init is the default value of the Type, 0 in this case. Therefore, you get 0 in the print。

use scalac -Xprint:all Test.scala, you will see the following:

 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>();
     ()
   }
 }

From the code, we can see that for normal initialization, init is set to 3 after the initialization of super class AbsCell2, when AbsCell2.this.init() gets invoked, it actually refers to the subclass' init field and 3 is yet to set, so we get the default type value。On the contrary, early initialization first set init to 3 then call super class initialization。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文