你如何在R中使用"<< - "(作用域分配)?

Tal*_*ili 122 r scoping lexical-scope r-faq

我刚读完R简介中的范围界定,对这项<<-任务非常好奇.

手册显示了一个(非常有趣)的例子<<-,我觉得我理解.我仍然缺少的是这可能有用的背景.

因此,我希望从您那里读到的是关于何时使用<<-可能有趣/有用的示例(或示例链接).使用它的危险可能是什么(它看起来容易松散),以及您可能想要分享的任何提示.

had*_*ley 171

<<-最有用的是与闭包相结合来维持状态.这是我最近的一篇论文的一节:

闭包是由另一个函数编写的函数.闭包是这样调用的,因为它们包含父函数的环境,并且可以访问该函数中的所有变量和参数.这很有用,因为它允许我们有两个级别的参数.一级参数(父级)控制函数的工作方式.另一个级别(孩子)完成工作.以下示例显示了如何使用此构思生成一系列电源功能.父函数(power)创建实际执行艰苦工作的子函数(squarecube).

power <- function(exponent) {
  function(x) x ^ exponent
}

square <- power(2)
square(2) # -> [1] 4
square(4) # -> [1] 16

cube <- power(3)
cube(2) # -> [1] 8
cube(4) # -> [1] 64
Run Code Online (Sandbox Code Playgroud)

管理两个级别的变量的能力还允许通过允许函数修改其父级环境中的变量来跨函数调用维护状态.管理不同级别变量的关键是双箭头赋值运算符 <<-.与通常<-在当前级别上工作的单箭头赋值()不同,双箭头运算符可以修改父级别中的变量.

这使得可以维护一个记录函数被调用次数的计数器,如下例所示.每次new_counter运行时,它都会创建一个环境,i在此环境中初始化计数器,然后创建一个新函数.

new_counter <- function() {
  i <- 0
  function() {
    # do something useful, then ...
    i <<- i + 1
    i
  }
}
Run Code Online (Sandbox Code Playgroud)

新函数是一个闭包,它的环境是封闭的环境.当闭包counter_onecounter_two运行时,每个闭包在其封闭环境中修改计数器,然后返回当前计数.

counter_one <- new_counter()
counter_two <- new_counter()

counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1
Run Code Online (Sandbox Code Playgroud)

  • 嘿,这是一个关于Rosettacode的未解决的R任务(http://rosettacode.org/wiki/Accumulator_factory#R)嗯,它是...... (3认同)

Sha*_*ane 33

它有助于将其<<-视为等效assign(如果您inherits将该函数中的参数设置为TRUE).的好处assign是,它允许您指定更多的参数(例如环境),所以我更喜欢使用assign<<-大多数情况下.

使用<<-assign(x, value, inherits=TRUE)意味着"搜索所提供环境的封闭环境,直到遇到变量'x'." 换句话说,它将按顺序继续遍历环境,直到找到具有该名称的变量,并将其分配给该变量.这可以在函数的范围内,也可以在全局环境中.

为了理解这些函数的作用,您还需要了解R环境(例如使用search).

我在运行大型模拟时经常使用这些功能,我想保存中间结果.这允许您创建给定函数或apply循环范围之外的对象.这非常有用,特别是如果您对大循环意外结束有任何疑虑(例如数据库断开连接),在这种情况下您可能会丢失过程中的所有内容.这相当于在长时间运行的过程中将结果写入数据库或文件,除了它将结果存储在R环境中.

我对此的主要警告是:小心,因为您现在正在使用全局变量,尤其是在使用时<<-.这意味着当您希望它使用作为参数提供的函数时,您最终可能会遇到函数正在使用环境中的对象值的情况.这是函数式编程试图避免的主要内容之一(参见副作用).我避免这个问题通过赋予我的价值观为唯一的变量名(使用贴有一组或唯一参数)从来没有在函数内使用,但只是用于缓存,并在情况下,我需要恢复以后(或者做一些元 - 对中间结果的分析).

  • 谢谢塔尔.我有一个博客,虽然我没有真正使用它.我永远无法完成一个帖子,因为我不想发布任何内容,除非它是完美的,我只是没有时间... (3认同)
  • 曾经有位智者对我说,保持完美并不重要-仅表现突出-您的身份,职位也会如此。另外-有时读者会通过注释来帮助改进文本(这就是我的博客所发生的情况)。我希望有一天你会重新考虑:) (2认同)

Dir*_*tel 8

我使用的一个地方<<-是使用tcl/tk的简单GUI.一些最初的例子有它 - 因为你需要区分localfullness的局部变量和全局变量.例如,参见

 library(tcltk)
 demo(tkdensity)
Run Code Online (Sandbox Code Playgroud)

哪个使用<<-.否则我同意Marek :) - Google搜索可以提供帮助.


Mat*_*ise 6

在这个主题上,我想指出,<<-当在 for 循环中(错误地)应用时,运算符的行为会很奇怪(也可能有其他情况)。鉴于以下代码:

fortest <- function() {
    mySum <- 0
    for (i in c(1, 2, 3)) {
        mySum <<- mySum + i
    }
    mySum
}
Run Code Online (Sandbox Code Playgroud)

您可能期望该函数会返回预期的总和 6,但它返回 0,并mySum创建了一个全局变量并分配了值 3。我无法完全解释这里发生的事情,但可以肯定的是 for 的主体循环不是新的范围“级别”。相反,R 似乎在fortest函数之外,找不到mySum要分配给的变量,因此第一次通过循环创建一个并分配值 1。在后续迭代中,赋值中的 RHS 必须指代(未更改的)内部mySum变量,而 LHS 指代全局变量。因此,每次迭代都会将全局变量的值覆盖为该迭代的值i,因此它在退出函数时具有值 3。

希望这对某人有所帮助-今天这让我难住了几个小时!(顺便说一句,只需替换<<-<-,该功能按预期工作)。

  • 在您的示例中,本地 `mySum` 永远不会增加,而只会增加全局 `mySum`。因此,在 for 循环的每次迭代中,全局 `mySum` 获得值 `0 + i`。您可以使用 `debug(fortest)` 来执行此操作。 (2认同)

小智 5

f <- function(n, x0) {x <- x0; replicate(n, (function(){x <<- x+rnorm(1)})())}
plot(f(1000,0),typ="l")
Run Code Online (Sandbox Code Playgroud)

  • 这是 _not_ 使用 `&lt;&lt;-` 的一个很好的例子。在这种情况下,for 循环会更清晰。 (11认同)