在R语言中,assign()和<<-有什么区别?

14

我理解,R语言中编写函数的常规方法是避免副作用(side-effects),并从函数返回一个值。

contained <- function(x) {
  x_squared <- x^2
  return(x_squared)
}

在这种情况下,函数计算输入值并返回结果。但是变量x_squared不可用。

但是,如果您需要违反这个基本的函数式编程原则(我不确定R语言对此问题有多严重),从函数中返回一个对象,您有两个选择。

escape <- function(x){
  x_squared  <<- x^2
  assign("x_times_x", x*x, envir = .GlobalEnv)
}

两个对象x_squaredx_times_x都被返回。是否有一种方法比另一种更好,为什么?

3个回答

20

托马斯·兰利在r-help论坛上于几天前进行了精彩的回答。<<- 是关于封闭环境的,因此您可以像这样做事情(我再次引用他4月22日的帖子在这个帖子中):

make.accumulator<-function(){
    a <- 0
    function(x) {
        a <<- a + x
        a
    }
}

> f<-make.accumulator()
> f(1)
[1] 1
> f(1)
[1] 2
> f(11)
[1] 13
> f(11)
[1] 24

这是一个合法的使用<<作为具有词法作用域的“超级赋值”的示例,而不仅仅是在全局环境中分配。对此,Thomas有这样的话:

邪恶和错误的用法是修改全局环境中的变量。

非常好的建议。

1
也许你应该链接到它 - Henry
谢谢,Dirk。我一直担心<<-会有恶意应用,这个正确性和良好性的示例帮助澄清了这个问题。Lumley先生加一分。 - Milktrader

2
根据这里的手册页面,<<-->>运算符会在环境中搜索所赋值变量的现有定义。在实践中我从未使用过这种方式,但在我的看法中,assign命令因为可以精确指定环境,甚至无需考虑R的作用域规则,因此更为优秀。而<<-则需要在多个环境中进行搜索,因此解释起来略微困难。
编辑:为了尊重@Dirk和@Hadley,实际上当您需要将值分配给全局环境时,assign是适当的方法,而<<-则是向更广泛的范围“提升”的适当方式。

2
是的,但通常您不知道要分配的环境确切位置在哪里。对于大多数情况,<<- 是正确的选择。 - hadley
@hadley 我记得曾经有人考虑将 <<- 从 R 中移除作为一个操作符。 - Milktrader
如果你问我,我觉得没有机会,因为这将需要大量的现有代码。R通常不会努力做到这一点。 - Dirk Eddelbuettel

0
正如@John在他的回答中指出的那样,assign允许您明确指定环境。一个具体的应用程序将如下所示:
testfn <- function(x){

    x_squared <- NULL

    escape <- function(x){
        x_squared  <<- x^2
        assign("x_times_x", x*x, envir = parent.frame(n = 1))
    }

    escape(x)

    print(x_squared)
    print(x_times_x)
}

我们在编程中同时使用<<-assign。请注意,如果您想使用<<-将变量赋值给顶层函数的环境,您需要声明/初始化该变量。但是,使用assign,您可以使用parent.frame(1)来指定封装环境。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接