在闭包中变量变量

时间:2014-04-26 16:16:14

标签: r scope closures

我对R很新,但是来自Scheme--它也是词法范围并且有闭包 - 我希望能够在闭包中改变外部变量。

,例如

foo <- function() {
  s <- 100

  add <- function() {
    s <- s + 1
  }

  add()
  s
}

cat(foo(), "\n") # prints 100 and not 101

我希望foo()返回101,但它实际上返回100:

$ Rscript foo.R
100

我知道Python有global关键字来声明变量的范围(虽然不能使用这个例子)。 R需要类似的东西吗?

我做错了什么?

更新

啊,add我在创建一个的局部变量s是否会影响外部s的问题?如果是这样,我如何在不创建局部变量的情况下改变s

3 个答案:

答案 0 :(得分:3)

使用<<-运算符在add()函数中进行分配。

来自?"<<-"

  

运算符<<-->>通常仅在函数中使用,并导致通过父环境搜索所分配变量的现有定义。如果找到这样的变量(并且其绑定未被锁定),则重新定义其值,否则在全局环境中进行赋值。请注意,它们的语义与S语言的语义不同,但与R的范围规则结合使用时,请参阅“R语言定义”手册以获取更多详细信息和示例。

答案 1 :(得分:3)

您还可以使用assign并使用envir参数精确定义范围,在<<-函数中的工作方式与add的工作方式相同,但是意图更清楚一点:

foo <- function() {
  s <- 100

  add <- function() {
   assign("s", s + 1, envir = parent.frame())
  }

  add()
  s
}

cat(foo(), "\n") 

当然,在R中这种事情的更好方法是让你的函数返回它修改的变量(或变量),并明确地将它们重新分配给原始变量:

foo <- function() {
  s <- 100
  add <- function(x) x + 1
  s <- add(s)
  s
}

cat(foo(), "\n") 

答案 2 :(得分:2)

以下是一种比assign<<-方法更安全的方法:

foo <- function() {
    e <- environment()
    s <- 100

    add <- function() {
        e$s <- e$s + 1
    }

    add()
    s
}

foo()

<<-分配可能会导致问题,如果您不小心拼错了变量名称,它仍会执行某些操作,但它不会是您所期望的,并且很难找到问题的根源。如果您想将add函数移动到另一个函数内部,或者从另一个函数调用它,那么assign方法可能会很棘手。总体上最好的方法是不让函数修改变量超出它们自己的范围,并让函数返回任何重要的东西。但是当不可能时,上面的方法使用词法作用域来访问环境e,然后分配到环境中,因此它将始终专门分配给该函数,从不在上面或下面。