R:范围、时间和 <<-

R: Scoping, timing, and <<-

在下面的代码中,我希望 f 和最后的 a 都为 return 3。但实际上它们都是 return 2。这是为什么?在评估 promise 时,封闭环境中的 3 是否已替换 2?

a <- 1

f <- function(a){
  a <<- 3
  cat(a)
}

f(a <- 2)
a

请注意,如果我在对 f 的调用中使用 = 而不是 <-,则最终 a 为预期的 3,但 f 仍为 2。

让我们看一下代码

a <- 1 

将值 1 分配给全局环境中的名称 a

f <- function(a){...}

在全局环境中创建一个保存到名称 f 的函数。

f(a <- 2)

现在我们使用表达式 a<-2 作为参数调用函数 f。该表达式不会立即求值。它作为承诺传递。 a 的全局值保持为 1。

现在我们进入函数体f。我们传入的表达式被分配给函数范围内的局部变量 a(仍未计算)和全局变量 a 仍然是 1。事实上它们都涉及符号 a 无关紧要。这里的两个a变量之间没有直接联系。

a <<- 3

这会通过 <<- 将值 3 分配给父作用域中的 a,而不是像 <- 那样分配给本地作用域。这意味着这里引用的 a 不是现在保存传递给函数的参数的局部 a。所以这会将全局范围内 a 的值更改为 3。最后

cat(a)

现在我们终于使用传递给函数的值,因为这里的 a 指的是局部函数作用域中的 a。这会触发 promise a <- 2 在调用范围(恰好是全局范围)中成为 运行。因此 a 的全局值设置为 2。此赋值表达式 returns 右侧值,因此从 cat().

显示“2”

函数退出并且

a

显示 a 在全局环境中的值,现在是 af.

中两个表达式之间的短暂时刻只有值3

如果你在哪里打电话

f( a=2 )

这是非常不同的。现在我们不再将表达式传递给函数,我们将值 2 传递给命名函数参数 a。如果您尝试使用 f(x=2),您将收到一个错误消息,即该函数无法识别名为 "x" 的参数。由于 2 是常数,因此在这种情况下没有奇特的惰性 expression/promise 评估。这将在函数调用后将全局值设置为 3。 f(a <- 2)f(a = a <- 2) 的行为方式相同。