为什么在system.time()中计算表达式会使变量在全局环境中可用?

And*_*rie 12 scope r

有人可以解释在评估表达式时会发生什么system.time?特别是,为什么expr参数中声明的变量在全局环境中可见?

system.time除了评估传递给函数的表达式之外,这里只是内部版本的精简版本:

st <- function(expr){
  expr
}

st(aa <- 1)
aa
[1] 1
Run Code Online (Sandbox Code Playgroud)

显然,这样做的结果是它aa在全局环境中创建了变量.这让我感到困惑,因为我认为在函数内部赋值变量使其在范围内是局部的.

这里发生了什么?

Jos*_*ien 14

这是因为提供的参数在调用函数的评估框架中进行评估(如R语言定义文档的第4.3.3节所述).

用户包装的表达式system.time()是一个提供的参数,它与位置匹配expr.然后,当expr在体内强制system.time进行评估时,在调用函数的评估框架中对其进行评估.如果system.time()从中调用.GlobalEnv,那么将发生任何作业的任务expr.

编辑:

这是一个示例,显示expr如果它是提供的(但不是默认的)参数,则在全局环境中进行评估.

st2 <- function(expr = newVar <- 33){
   expr
}

# Using the default argument -- eval and assignment 
# within evaluation frame of the function. 
st2()
newVar
Error: object 'newVar' not found

# Using a supplied argument -- eval and assignment
# within the calling function's evaluation frame (here .GlobalEnv)
st2(newVar <- 44)
newVar
# [1] 44
Run Code Online (Sandbox Code Playgroud)


Jor*_*eys 6

编辑:根据@ Tommy的评论:评估实际上只在使用参数expr时发生(这是懒惰的评估).

传递的是语言对象,而不是表达式.你基本上嵌套<-函数(两个参数)的ST()函数调用中,而结果的的<-调用被传递到圣.如您所见?assignOps,该<-函数以静默方式返回指定的值.正如@Josh告诉你的那样,嵌套函数的这种评估发生在调用函数的环境中.

你做的,相当于

st(mean(1:10))
Run Code Online (Sandbox Code Playgroud)

要看到差异,您可以:

st <- function(expr){
  typeof(expr)
}
> st(aa <- 1)
[1] "double"
> st(expression(aa <- 1))
[1] "expression"
Run Code Online (Sandbox Code Playgroud)

对于呼叫的结构,您可以:

st <- function(expr){
  str(as.list(match.call()))
}
> st(mean(1:10))
List of 2
 $     : symbol st
 $ expr: language mean(1:10)
> st(aa <- 1)
List of 2
 $     : symbol st
 $ expr: language aa <- 1
Run Code Online (Sandbox Code Playgroud)