我正在浏览effective scala slides并且它在幻灯片10中提到永远不要在 trait
中使用 val
来抽象成员并使用 def
代替 . 幻灯片没有详细提及为什么在 trait
中使用抽象 val
是反模式 . 如果有人可以解释在抽象方法的特性中使用val vs def的最佳实践,我将不胜感激
我正在浏览effective scala slides并且它在幻灯片10中提到永远不要在 trait
中使用 val
来抽象成员并使用 def
代替 . 幻灯片没有详细提及为什么在 trait
中使用抽象 val
是反模式 . 如果有人可以解释在抽象方法的特性中使用val vs def的最佳实践,我将不胜感激
3 回答
def
可以由def
,val
,lazy val
或object
实现 . 所以这是定义成员最抽象的形式 . 因为traits通常是抽象接口,所以你想要val
说明实现应该如何做 . 如果你要求val
,实现类不能使用def
.仅当您需要稳定的标识符时才需要
val
,例如对于路径依赖类型 . 那是's something you usually don't需要 .相比:
如果你有
你将无法定义
F1
或F3
.好的,混淆你并回答@ om-nom-nom-using abstract
val
s会导致初始化问题:这是一个丑陋的问题,在我个人看来,它应该在未来的Scala版本中通过修复它在编译器中消失,但是,是的,目前这也是为什么不应该使用abstract
val
s的原因 .Edit (2016年1月):您可以使用
lazy val
实现覆盖抽象val
声明,这样也可以防止初始化失败 .我不喜欢在特征中使用
val
因为val声明具有不清楚且不直观的初始化顺序 . 你可以在已经工作的层次结构中添加一个特征,它会破坏之前工作的所有东西,请参阅我的主题:why using plain val in non-final classes你应该记住使用这个val声明的所有事情,这最终会导致你的错误 .
使用更复杂的示例进行更新
但有些时候你无法避免使用
val
. 正如@ 0__有时提到你需要一个稳定的标识符而def
不是一个 .我举一个例子来说明他在说什么:
此代码生成错误:
如果你花一点时间认为你会理解编译器有理由抱怨 . 在
Access2.access
情况下,它无法通过任何方式获得返回类型 .def holder
意味着它可以广泛实施 . 它可以为每次调用返回不同的持有者,并且持有者将包含不同的Inner
类型 . 但Java虚拟机需要返回相同的类型 .总是使用def看起来有点尴尬,因为这样的东西不起作用:
您将收到以下错误: