R 中从函数到全局环境的绑定值

Binding values from function to global environment in R

我无法理解如何将函数内的值绑定到函数外的环境。下面显示了一个基本示例,我似乎无法解决函数的最后一部分:

number <- data.frame()

how_many_fruits <- function() {

    answer <- as.integer(readline(prompt="How Many?: "))
    globalenv()$number <- rbind(globalenv()$number, answer)

}

本质上,我想在开始时有一个名为number的空数据框,每次how_many_fruits()是运行,我希望输入附加到底部number 数据框。

您可以使用 <<- 运算符:

number <- data.frame()
how_many_fruits <- function() {

  answer <- as.integer(readline(prompt="How Many?: "))  
  number <<- rbind(number, answer)

}

但是,我想知道您对该程序的目标是什么。函数不应该像您那样在全局环境中使用变量。如果有人想使用那个函数,但调用变量 num 而不是 number,会发生什么?该功能在那种情况下不起作用。所以我建议您改为执行以下操作:

how_many_fruits <- function(num) {

  answer <- as.integer(readline(prompt="How Many?: "))
  new_num <- rbind(num, answer)

  return (new_num)
}

number <- data.frame()
number <- how_many_fruits(number)

这就是一个函数应该如何工作:它接受输入(此处称为 num)并 returns 输出(此处称为 new_num)。请注意输入和输出的名称 inside 函数不必与您在函数 outside 中使用的变量名称相同。当您调用 how_many_fruits(number) 时,number 的内容存储在 num 中,该函数仅适用于后者。当您执行 number <- how_many_fruits(number) 时,作为 how_many_fruits(number) 结果返回的任何内容都存储在 number.

直接从函数中修改全局环境不是一个好主意。通常,只 return 一个值并让用户将其附加到需要的地方是一个更好的主意。 (正如 Stibu 解释的那样)。

但是,您也可以使用嵌套环境,如下面对官方 R 语言定义中的示例进行的修改:

fruitscollector <- function(){
  fruitslist <- NULL
  function(){
    answer <- as.integer(readline(prompt="How Many?: "))
    fruitslist <<- c(fruitslist, answer)
    fruitslist
  }
}

所以当您第一次初始化一个 "fruitscollector" 时,它 return 只是一个可以收集值的函数。

foo <- fruitscollector()

现在每次使用 foo 时,都会将一个值添加到集合中(整个集合是 returned):

foo()
foo()
# etc

fruitslist 存储在 foo 的父环境中,因此不在您可能会意外删除它的全局环境中。

编辑

一个更一般的想法是创建一个对象(有点类似于 OOP 中所谓的 "object"),函数作为方法,例如

collector <- function(){
  stack <- NULL
  list(
    add = function(x) stack<<-c(stack, x),
    get = function() stack,
    empty = function() stack <<- NULL
  )
}

现在 add 方法将添加到堆栈,get 方法将 return 整个堆栈,而 empty 方法将清空它。

foo <- collector()  # initialize
foo$get()  # NULL
foo$add(1)  # add 1 to the stack
foo$get()  # 1
foo$add(3)  # add 3 to the stack
foo$get()  # 1 3
foo$add(1:5) # etc...