简体   繁体   English

scala,初始化抽象vals

[英]scala, Initializing abstract vals

the book "Programming in Scala, Third Edition, Martin Odersky" gives this example on page 449: “Scala编程,第三版,Martin Odersky”一书在第449页给出了这个例子:

trait RationalTrait {
  val numerArg: Int
  val denomArg: Int
  require(denomArg != 0)
  private val g = gcd(numerArg, denomArg)
  val numer = numerArg / g
  val denom = denomArg / g
  private def gcd(a: Int, b: Int): Int =
    if (b == 0) a else gcd(b, a % b)
  override def toString = numer + "/" + denom
}

and then it explains that the following code fails because the trait is initialized before the anonymous class, and so, denomArg is still 0. 然后它解释了以下代码失败,因为trait在匿名类之前被初始化,因此,denomArg仍为0。

new RationalTrait {
  val numerArg = 4
  val denomArg = 24
}

and it provides two solutions. 它提供了两种解决方案。 One solution is to use pre-initialized fields: 一种解决方案是使用预先初始化的字段:

new {
  val numerArg = 4
  val denomArg = 24
} with RationalTrait

the second solution is to modify the trait to use lazy values, as follows: 第二种解决方案是修改特性以使用延迟值,如下所示:

trait LazyRationalTrait {
  val numerArg: Int
  val denomArg: Int
  lazy val numer = numerArg / g
  lazy val denom = denomArg / g
  override def toString = numer + "/" + denom
  private lazy val g = {
    require(denomArg != 0)
    gcd(numerArg, denomArg)
  }
  private def gcd(a: Int, b: Int): Int =
    if (b == 0) a else gcd(b, a % b)
}

new LazyRationalTrait {
  lazy val numerArg = 4
  lazy val denomArg = 24
}

However, this simpler solution also works. 但是,这个更简单的解决方案也有效。 I wonder why they did not mention this solution. 我想知道为什么他们没有提到这个解决方案。 Is there any drawback in this? 这有什么缺点吗?

new RationalTrait {
  lazy val numerArg = 4
  lazy val denomArg = 24
}

I would consider your solution as more consistent comparing to the second option (mentioned on page 453 of Programming Scala, 3d ed.): 我认为你的解决方案与第二个选项相比更加一致(在Scala编程的第453页提到,3d ed。):

trait A { 
  val x: Int 
  lazy val y: Int = x
  val z: Int = y 
}

new A { val x = 1 }.y        // ==0 ?!!!
new A { val x = 1 }.z        // ==0 ?!!!

vs VS

trait A { 
  val x: Int 
  val y: Int = x
  val z: Int = y 
}

new A { lazy val x = 1 }.y   // ==1
new A { lazy val x = 1 }.z   // ==1

At least I don't need to remember that lazy val s can't be used in non-lazy constructs in the base class. 至少我不需要记住懒惰的val不能用在基类的非延迟构造中。 Looking at the bytecode I don't see any obvious problems with your approach since in the latter case x is effectively defined as def so it already exists when initialization starts in the base class. 查看字节码我没有看到你的方法有任何明显的问题,因为在后一种情况下, x被有效地定义为def所以它在基类中初始化时已经存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM