动态改变函数scala
Dynamically changing functions scala
我正在学习 scala,并且遇到了以下代码。
def whileLoop(cond: => Boolean)(body: => Unit): Unit =
if (cond) {
body
whileLoop(cond)(body)
}
var i = 10
whileLoop (i > 0) {
println(i)
i -= 1
}
输出是数字 10 到 1。
所以cond和body都是"call by name"参数。这意味着它们在函数中使用时会被评估。如果我理解正确的话。我不明白的是 body
println(i)
i -= 1
应用的每个递归级别的变化 body 随着变量 i 的变化而变化。但这究竟是如何工作的呢?每次传递相同的函数 body 时,对我来说这个函数都保持不变,但 运行 程序向我显示其他情况。我知道函数每次都会被求值,但我不明白里面的 i 变量每次是如何变化的,所以有人能解释一下它是如何工作的吗?
当您声明类型为 => Type
的参数时,您将该参数声明为匿名函数(该函数仅 returns 而 Type
没有任何输入)。
因此,当第一次调用该函数时,每个参数每次都会针对 i
的特定值进行评估。
由于 body
会在每次迭代中更改 i
值,因此程序将在每次 body
更改时重新计算 i
。
我知道这听起来很复杂,但请耐心等待。让我们看看当您删除 =>
.
时会发生什么
如果您删除 =>
,您就不会声明要重新评估的匿名函数。您正在定义无法重写的参数。并且由于不能每次都重新评估条件,您将有一个无限的bucle。
希望这个解释能给您一些帮助。
在这个例子中,主体
println(i)
i -= 1
是对变量 i
进行操作的 closure,它在正文定义的范围内。因此 i
不是主体的局部变量,这意味着操作 -=
修改唯一存在的值 i
,而不是在方法调用后被丢弃的本地副本。
条件也是如此:它是一个捕获相同变量 i
的闭包,因此在每次执行主体后,条件将看到现在更新的值 i
.
让我们在不改变含义的情况下稍微重写一下示例:首先,我们可以重写 whileLoop
以将函数作为参数而不是按名称调用的参数:
def whileLoop(cond: () => Boolean)(body: () => Unit): Unit =
if (cond()) {
body()
whileLoop(cond)(body)
}
这个重写的 whileLoop
在语义上是相同的,因为按名称调用的参数是作为表达式而不是表达式的求值传递的。免责声明:我不知道是否存在技术差异,例如性能方面的差异。
其次,我们可以使传递给 cond
和 body
函数的表达式不带参数:
val condDef = () => i > 0
val bodyDef = () => {
println(i)
i -= 1
}
因为它们都引用了变量 i
,它既不是它们的参数的一部分,也不是在它们的主体中定义的,我们必须将 i
放在它们的范围内。
def main(args: Array[String]) {
var i = 10
val condDef = () => i > 0
val bodyDef = () => {
println(i)
i -= 1
}
whileLoop (condDef) {
bodyDef
}
}
所以 i
可以从 condDef
和 bodyDef
访问,并且在计算它们时可以访问和修改。
i -= 1 获取变量 i 并将其重新分配给其减 1 的值。
您的 body 引用同一个 i 变量,每次调用 body 时都会修改该变量。
忽略所有递归和你的 whileLoop 本质上它是这样做的:
var i = 10
println(i) // prints 10
i -= 1
println(i) // prints 9
i -= 1
...
i -= 1
println(i) // prints 1
i -= 1
println(i) // prints 0
我正在学习 scala,并且遇到了以下代码。
def whileLoop(cond: => Boolean)(body: => Unit): Unit =
if (cond) {
body
whileLoop(cond)(body)
}
var i = 10
whileLoop (i > 0) {
println(i)
i -= 1
}
输出是数字 10 到 1。
所以cond和body都是"call by name"参数。这意味着它们在函数中使用时会被评估。如果我理解正确的话。我不明白的是 body
println(i)
i -= 1
应用的每个递归级别的变化 body 随着变量 i 的变化而变化。但这究竟是如何工作的呢?每次传递相同的函数 body 时,对我来说这个函数都保持不变,但 运行 程序向我显示其他情况。我知道函数每次都会被求值,但我不明白里面的 i 变量每次是如何变化的,所以有人能解释一下它是如何工作的吗?
当您声明类型为 => Type
的参数时,您将该参数声明为匿名函数(该函数仅 returns 而 Type
没有任何输入)。
因此,当第一次调用该函数时,每个参数每次都会针对 i
的特定值进行评估。
由于 body
会在每次迭代中更改 i
值,因此程序将在每次 body
更改时重新计算 i
。
我知道这听起来很复杂,但请耐心等待。让我们看看当您删除 =>
.
如果您删除 =>
,您就不会声明要重新评估的匿名函数。您正在定义无法重写的参数。并且由于不能每次都重新评估条件,您将有一个无限的bucle。
希望这个解释能给您一些帮助。
在这个例子中,主体
println(i)
i -= 1
是对变量 i
进行操作的 closure,它在正文定义的范围内。因此 i
不是主体的局部变量,这意味着操作 -=
修改唯一存在的值 i
,而不是在方法调用后被丢弃的本地副本。
条件也是如此:它是一个捕获相同变量 i
的闭包,因此在每次执行主体后,条件将看到现在更新的值 i
.
让我们在不改变含义的情况下稍微重写一下示例:首先,我们可以重写 whileLoop
以将函数作为参数而不是按名称调用的参数:
def whileLoop(cond: () => Boolean)(body: () => Unit): Unit =
if (cond()) {
body()
whileLoop(cond)(body)
}
这个重写的 whileLoop
在语义上是相同的,因为按名称调用的参数是作为表达式而不是表达式的求值传递的。免责声明:我不知道是否存在技术差异,例如性能方面的差异。
其次,我们可以使传递给 cond
和 body
函数的表达式不带参数:
val condDef = () => i > 0
val bodyDef = () => {
println(i)
i -= 1
}
因为它们都引用了变量 i
,它既不是它们的参数的一部分,也不是在它们的主体中定义的,我们必须将 i
放在它们的范围内。
def main(args: Array[String]) {
var i = 10
val condDef = () => i > 0
val bodyDef = () => {
println(i)
i -= 1
}
whileLoop (condDef) {
bodyDef
}
}
所以 i
可以从 condDef
和 bodyDef
访问,并且在计算它们时可以访问和修改。
i -= 1 获取变量 i 并将其重新分配给其减 1 的值。 您的 body 引用同一个 i 变量,每次调用 body 时都会修改该变量。 忽略所有递归和你的 whileLoop 本质上它是这样做的:
var i = 10
println(i) // prints 10
i -= 1
println(i) // prints 9
i -= 1
...
i -= 1
println(i) // prints 1
i -= 1
println(i) // prints 0