30

我经常编写需要查看环境中其他对象的函数。例如:

> a <- 3
> b <- 3
> x <- 1:5
> fn1 <- function(x,a,b) a+b+x
> fn2 <- function(x) a+b+x
> fn1(x,a,b)
[1]  7  8  9 10 11
> fn2(x)
[1]  7  8  9 10 11

正如所料,这两个函数是相同的,因为fn2在执行时可以“看到” a 和 b。但是每当我开始利用这一点时,在大约 30 分钟内,我最终会在没有必要变量之一(例如 a 或 b)的情况下调用该函数。如果我不利用这一点,那么我觉得我在不必要地传递物体。

明确说明函数需要什么会更好吗?还是应该通过内联注释或函数的其他文档来解决这个问题?有没有更好的办法?

4

4 回答 4

36

如果我知道我将需要一个由某些值参数化并重复调用的函数,我会通过使用闭包来避免全局变量:

make.fn2 <- function(a, b) {
    fn2 <- function(x) {
        return( x + a + b )
    }
    return( fn2 )
}

a <- 2; b <- 3
fn2.1 <- make.fn2(a, b)
fn2.1(3)    # 8
fn2.1(4)    # 9

a <- 4
fn2.2 <- make.fn2(a, b)
fn2.2(3)    # 10
fn2.1(3)    # 8

这巧妙地避免了引用全局变量,而是使用 a 和 b 函数的封闭环境。调用 fn2 实例时,全局变量 a 和 b 的修改不会导致意外的副作用。

于 2009-07-26T04:15:48.203 回答
8

某些语言不允许使用全局变量是有原因的:它们很容易导致代码损坏。

R 中的作用域规则允许您以懒惰的方式编写代码 - 让函数在其他环境中使用变量可以节省一些输入,并且非常适合在简单的情况下使用。

但是,如果您正在做任何远程复杂的事情,那么我建议您向函数传递它需要的所有变量(或者至少,在变量不存在的情况下进行一些彻底的完整性检查以备后备) .

在上面的例子中:

最佳做法是使用 fn1。

或者,尝试类似

 fn3 <- function(x)
   {
      if(!exists("a", envir=.GlobalEnv))
      {
         warning("Variable 'a' does not exist in the global environment")
         a <- 1
      }

      if(!exists("b", envir=.GlobalEnv))
      {
         warning("Variable 'b' does not exist in the global environment")
         b <- 2
      }

      x + a + b
   }
于 2009-07-23T08:49:28.443 回答
3

当您只是在函数中使用全局变量或尝试分配变量时是否会出现问题?如果是后者,我怀疑这是因为您没有<<-在函数中用作赋值。虽然使用<<-似乎是黑暗的一面1它可能非常适合您的目的。如果是前者,则该函数可能正在屏蔽全局变量。

以难以在本地屏蔽它们的方式命名全局变量可能会有所帮助。例如:global.pimultiples <- 1:4*pi

于 2009-07-23T05:15:11.433 回答
0

在大多数语言中,通常不鼓励使用全局变量,R 也不例外。短函数通常使用短的通用变量名,可以在全局环境中填充。a) 在函数定义中包含所有变量 b)分配默认值是最安全的。例如,写 f=function(a,b),而不是 f=function(a=0,b=NA)。

于 2009-07-24T01:13:09.007 回答