Scala 允许您像这样进行早期定义:
trait A {
val v: Int
}
class B extends { val v = 4 } with A
此功能的示例用法是什么?
每当该值用于特征初始化时。所以对于这个特征的例子:
trait UsefulTrait {
val parameter : Int
private val myHelperObject = new MyExpensiveClass(parameter)
}
该参数用于替代构造函数参数。然而,参数应该是一个抽象方法,因为它为实现者留下了更多的自由空间。
让我们看一下《Scala 编程》一书(第 451 页)中的一个示例。如果我们有这样的定义:
trait RationalTrait {
val numerArg: Int
val denomArg: Int
}
然后 numerArg 和 denomArg 被称为抽象 vals & trait 可以直接使用而无需扩展,如下所示:
val x = new RationalTrait {
val numerArg = 1
val denomArg = 2
}
或者
val y = new {
val numerArg = 1
val denomArg = 1
} with RationalTrait
以上两种都是trait 中 abstract val 的有效Pre-initializing ,除了需要将表达式值放入 abstract val 时,只能使用后面的形式,像这样:
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!")