声明或定义引入的名称范围是包含绑定的整个语句序列.然而,在块向前引用的限制:在一份声明序列
s[1]...s[n]组成一个块,如果一个简单的名字s[i]指的是一个实体的定义s[j]在那里j >= i,那么对于所有s[k]之间,包括s[i]和s[j],
s[k]不能是变量定义.- 如果
s[k]是值定义,则必须是lazy.
编辑:我不确定MikaëlMayer的答案是否真的解释了一切.考虑:
object Test {
def main(args: Array[String]) {
println(x)
lazy val x: Int = 6
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,x必须在代码中实际定义之前读取/评估惰性值!这与Mikaël声称懒惰评估消除了在定义之前评估事物的需要相矛盾.
通常你不能这样:
val e: Int = 2
val a: Int = b+c
val b: Int = c
val c: Int = 1
val d: Int = 0
Run Code Online (Sandbox Code Playgroud)
因为在定义a时尚未定义值c.因为引用c,a和c之间的所有值都应该是惰性的,以避免依赖
val e: Int = 2
lazy val a: Int = b+c
lazy val b: Int = c
lazy val c: Int = 1
val d: Int = 0
Run Code Online (Sandbox Code Playgroud)
这实际上将a,b和c转换为在读取时初始化其值的对象,这将在声明之后,即这相当于:
val e: Int = 2
var a: LazyEval[Int] = null
var b: LazyEval[Int] = null
var c: LazyEval[Int] = null
a = new LazyEval[Int] {
def evalInternal() = b.eval() + c.eval()
}
b = new LazyEval[Int] {
def evalInternal() = c.eval()
}
c = new LazyEval[Int] {
def evalInternal() = 1
}
val d = 0
Run Code Online (Sandbox Code Playgroud)
LazyEval将在何处(如下所示)(由编译器本身实现)
class LazyEval[T] {
var value: T = _
var computed: Boolean = false
def evalInternal(): T // Abstract method to be overriden
def eval(): T = {
if(computed) value else {
value = evalInternal()
computed = true
value
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑
vals在java中并不存在.它们是局部变量或在计算中不存在.因此,lazy val的声明在任何事情发生之前就存在了.请记住,闭包是在Scala中实现的.您的块将被重写为:
object Test {
def main(args: Array[String]) {
// Declare all variables, val, vars.
var x: Lazy[Int] = null
// No more variables to declare. Lazy/or not variable definitions
x = new LazyEval[Int] {
def evalInternal() = 6
}
// Now the code starts
println(x)
}
}
| 归档时间: |
|
| 查看次数: |
748 次 |
| 最近记录: |