Scala:用于早期定义/早期初始值设定项/预初始化字段的示例

Scala:用于早期定义/早期初始值设定项/预初始化字段的示例,scala,traits,Scala,Traits,Scala允许您做出如下早期定义: trait A { val v: Int } class B extends { val v = 4 } with A 此功能的示例用途是什么?每当该值用于特征初始化时。因此,对于该特性的EAX示例: trait UsefulTrait { val parameter : Int private val myHelperObject = new MyExpensiveClass(parameter) } 该参数用于替换构造函数参数。然而,参数

Scala允许您做出如下早期定义:

trait A {
  val v: Int
}

class B extends { val v = 4 } with A

此功能的示例用途是什么?

每当该值用于特征初始化时。因此,对于该特性的EAX示例:

trait UsefulTrait {
  val parameter : Int
  private val myHelperObject = new MyExpensiveClass(parameter)
}

该参数用于替换构造函数参数。然而,参数应该是一个抽象的方法,因为它为实现者留下了更多的自由空间。

让我们看看Scala书籍中的编程示例(第451页)。如果我们有这样的定义:

trait RationalTrait {
   val numerArg: Int
   val denomArg: Int
}
val x = new RationalTrait {
   val numerArg = 1
   val denomArg = 2
}
val z = new {
  val numerArg = 1 * x
  val denomArg = 2 * x
} with RationalTrait
然后numerArg和denomArg被称为抽象vals&trait可以不使用extends直接使用,如下所示:

trait RationalTrait {
   val numerArg: Int
   val denomArg: Int
}
val x = new RationalTrait {
   val numerArg = 1
   val denomArg = 2
}
val z = new {
  val numerArg = 1 * x
  val denomArg = 2 * x
} with RationalTrait

上述两种都是trait中抽象val的有效预初始化,除了需要将表达式值放入抽象val时,只能使用后一种形式,如下所示:

trait RationalTrait {
   val numerArg: Int
   val denomArg: Int
}
val x = new RationalTrait {
   val numerArg = 1
   val denomArg = 2
}
val z = new {
  val numerArg = 1 * x
  val denomArg = 2 * x
} with RationalTrait
本书中另一个有趣的例子是在类定义中预先初始化字段

class RationalClass(n: Int, d: Int) extends {
  val numerArg = n
  val denomArg = d
} with RationalTrait {
  def + (that: RationalClass) = new RationalClass(
    numer * that.denom + that.numer * denom,
    denom * that.denom
  )
}

特别是在单元测试中,您对单独测试特性感兴趣。在这种情况下,您需要创建一个与您感兴趣的特征混合的对象。这是一个例子:

trait Display {
  def show(msg: String) = ...
}

val o = new Object with Display
o.show("hey!")
另一种情况是,您的特质取决于注入的变量:

trait Logging {
  val stream: java.io.OutputStream
  def log(msg: String) = ...
}

val o = new { val stream = new FileOutputStream(...) } with Logging
o.log("hey!")

相关人员:好的,我明白了。但是,当它不应该成为一个抽象方法时,有什么例子呢?仅当您希望确保此值不发生更改时?@gzm0不必将trait声明为
val
。只要在初始化期间访问任何抽象成员,就会出现问题,因为实现类可能选择在那里使用
val