请注意,这个问题和类似的问题之前已经被问过,例如在前向引用中 - 为什么这段代码会编译?,但我找到了仍然留下一些问题的答案,所以我在这个问题上再试一次。
在方法和函数中,val
关键字的作用似乎是词法的,即
def foo {
println(bar)
val bar = 42
}
屈服
error: forward reference extends over definition of value bar
但是,在类中,范围规则val
似乎发生了变化:
object Foo {
def foo = bar
println(bar)
val bar = 42
}
这不仅会编译,而且构造println
函数中的0
foo
42
因此,方法似乎可以前向引用实例值,最终将在调用方法之前初始化(当然,除非您从构造函数调用它),以及构造函数中的语句以相同的方式转发引用值,在它们被初始化之前访问它们,从而产生一个愚蠢的任意值。
由此,出现了几个问题:
- 为什么
val
在构造函数中使用它的词法编译时效果?
鉴于构造函数实际上只是一个方法,这似乎与完全 dropval
的编译时效果不一致,只给它通常的运行时效果。
- 为什么
val
有效地失去了声明不可变值的效果?
在不同时间访问该值可能会导致不同的结果。对我来说,这很像是编译器实现细节的泄露。
- 合法的用例可能是什么样的?
我很难想出一个绝对需要val
内部构造函数的当前语义的示例,并且不容易用适当的词法实现val
,可能与lazy
.
- 一个人将如何解决这种行为
val
,从其他方法中使用它来取回一个习惯于使用它的所有保证?
可以推测,可以将所有 instance 声明val
为是lazy
为了回到val
不可变的状态并产生相同的结果,无论它们如何访问,并降低在常规方法中观察到的编译时效果的相关性,但这似乎对于这种事情,对我来说就像一个非常糟糕的黑客攻击。
鉴于这种行为在实际语言中不太可能发生变化,编译器插件是否是解决此问题的正确位置,或者是否可以实现val
-alike 关键字,对于刚刚花了一个小时调试由这种奇怪的,语言中更明智的语义?