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
在全局环境中的值,现在是 a
。 f
.
中两个表达式之间的短暂时刻只有值3
如果你在哪里打电话
f( a=2 )
这是非常不同的。现在我们不再将表达式传递给函数,我们将值 2 传递给命名函数参数 a
。如果您尝试使用 f(x=2)
,您将收到一个错误消息,即该函数无法识别名为 "x" 的参数。由于 2 是常数,因此在这种情况下没有奇特的惰性 expression/promise 评估。这将在函数调用后将全局值设置为 3。 f(a <- 2)
和 f(a = a <- 2)
的行为方式相同。
在下面的代码中,我希望 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()
.
函数退出并且
a
显示 a
在全局环境中的值,现在是 a
。 f
.
如果你在哪里打电话
f( a=2 )
这是非常不同的。现在我们不再将表达式传递给函数,我们将值 2 传递给命名函数参数 a
。如果您尝试使用 f(x=2)
,您将收到一个错误消息,即该函数无法识别名为 "x" 的参数。由于 2 是常数,因此在这种情况下没有奇特的惰性 expression/promise 评估。这将在函数调用后将全局值设置为 3。 f(a <- 2)
和 f(a = a <- 2)
的行为方式相同。