在R中编写函数,记住范围

Chr*_*ois 30 scope r

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

> 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
Run Code Online (Sandbox Code Playgroud)

正如所料,这两个函数都是相同的,因为它fn2可以在执行时"看到"a和b.但每当我开始利用这一点时,在大约30分钟内我最终调用函数时没有必要的变量(例如a或b).如果我没有利用这一点,那么我觉得我不必要地绕过物体.

是否更好地明确函数需要什么?或者应该通过内联注释或函数的其他文档来处理?有没有更好的办法?

ars*_*ars 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
Run Code Online (Sandbox Code Playgroud)

这样可以很好地避免引用全局变量,而是使用函数的封闭环境来表示a和b.当调用fn2实例时,修改全局变量a和b不会导致意外的副作用.


Ric*_*ton 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
   }
Run Code Online (Sandbox Code Playgroud)