在以下代码中:
trait Base {
val foo: String = {
println("Hi, I'm initializing foo in trait Base")
"foo"
}
}
class Overrider extends Base {
override val foo = "bar!"
}
object Runner extends App {
println(new Overrider().foo)
println((new {override val foo = "baz"} with Base).foo)
}
无论是否通过扩展特征或使用早期初始化来覆盖 val ,都会调用 Base
特征的foo
值初始化:
Hi, I'm initializing foo in trait Base
bar!
Hi, I'm initializing foo in trait Base
baz
有没有办法使用val
并避免发生这种情况,还是应该坚持使用lazy val
?
答案 0 :(得分:3)
如您所述使用lazy val
或def
。 AFAIK没有其他方法可以避免在基类中初始化val
。这是因为类成员定义之外的所有内容都进入构造函数。因此,val
s将在施工时初始化。
另一种方法是定义一个扩展的接口:
trait Base {
def foo: String
}
class Foo extends Base {
override val foo = "foo"
}
class Bar extends Base {
override val foo = "bar"
}
答案 1 :(得分:0)
当其他用户回答您的问题时,如果您不希望评估foo
特征方法,则必须将def
定义为Base
。
您在问题的评论中告诉我您正在尝试实施接线模块,如本link中所述。然后,你基本上试图实现薄蛋糕模式。
在这种情况下,将foo
声明为val
在逻辑上不正确。 foo
表示无法急切解决的依赖关系。如果使用val
,则两个组件将紧密耦合。您必须将foo
定义为def
,以便让您的主应用程序(或测试)将foo
连接到正确的类型,即具体类或模拟。
如果您想要更多解释,请告诉我。