动态改变函数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 在语义上是相同的,因为按名称调用的参数是作为表达式而不是表达式的求值传递的。免责声明:我不知道是否存在技术差异,例如性能方面的差异。

其次,我们可以使传递给 condbody 函数的表达式不带参数:

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 可以从 condDefbodyDef 访问,并且在计算它们时可以访问和修改。

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