在R中访问闭包中的变量

Rob*_*inL 9 closures r

在下面的例子,为什么f$if$get_i()返回不同的结果?

factory <- function() {

  my_list <- list()
  my_list$i <- 1

  my_list$increment <- function() {
    my_list$i <<- my_list$i + 1
  }

  my_list$get_i <- function() {
    my_list$i
  }

  my_list
}

f <- factory()

f$increment()
f$get_i() # returns 2
f$i # returns 1
Run Code Online (Sandbox Code Playgroud)

Łuk*_*yło 6

f <- factory()
Run Code Online (Sandbox Code Playgroud)

创建my_list对象my_list$i = 1并将其分配给f.所以现在f$i = 1.

f$increment() 
Run Code Online (Sandbox Code Playgroud)

my_list$i仅增量.它不会影响f.

现在

f$get_i() 
Run Code Online (Sandbox Code Playgroud)

返回(先前递增)my_list$iwhile

f$i 
Run Code Online (Sandbox Code Playgroud)

返回不受影响 f$i

它'因为您使用<<-了对全局对象进行操作的运算符.如果您将代码更改为

my_list$increment <- function(inverse) {
    my_list$i <- my_list$i + 1
}
Run Code Online (Sandbox Code Playgroud)

my_list将仅在increment函数内增加.所以现在你明白了

> f$get_i() 
[1] 1
> f$i 
[1] 1
Run Code Online (Sandbox Code Playgroud)

让我在你的代码中添加一行代码,这样我们就能看到increment肠子了:

 my_list$increment <- function(inverse) {
    my_list$i <- my_list$i + 1
    return(my_list$i)
  }
Run Code Online (Sandbox Code Playgroud)

现在,你可以看到<-里面只有工作increment,而<<-在它之外运行.

> f <- factory()
> f$increment()
[1] 2
> f$get_i() 
[1] 1
> f$i
[1] 1
Run Code Online (Sandbox Code Playgroud)


YCR*_*YCR 5

您编码的方式与功能范式非常相似。R 更常被用作脚本语言。因此,除非您确切地知道自己在做什么,否则使用 <<- 或在函数中包含函数是不好的做法。

你可以找到解释这里的功能环境的篇章。

环境是执行代码的空间/框架。环境可以嵌套,就像函数一样。

创建函数时,您附加了一个外壳环境,可以通过environment. 这是封闭环境。

该函数在另一个环境中执行,该执行环境采用全新启动原则。执行环境是封闭环境的子环境。

例如,在我的笔记本电脑上:

> environment()
<environment: R_GlobalEnv>
> environment(f$increment)
<environment: 0x0000000022365d58>
> environment(f$get_i)
<environment: 0x0000000022365d58>
Run Code Online (Sandbox Code Playgroud)

f 是位于全局环境中的对象。

该函数increment附有封闭环境 0x0000000022365d58,即函数的执行环境factory

我引用哈德利的话:

当你在另一个函数内部创建一个函数时,子函数的封闭环境是父函数的执行环境,执行环境不再是短暂的。

执行函数 f 时,会创建包含其中的my_list对象的封闭环境。

可以使用以下ls命令进行评估:

> ls(envir = environment(f$increment))
[1] "my_list"
> ls(envir = environment(f$get_i))
[1] "my_list"
Run Code Online (Sandbox Code Playgroud)

<<-运营商正在寻找在父母的环境中使用的变量。在这种情况下,my_list找到的对象是直接上层环境中的对象,即函数的封闭环境。

因此,当进行增量时,它仅在该环境中而不是在全局中进行。

您可以通过以下方式替换该increment功能来查看它:

  my_list$increment <- function() {
    print("environment")
    print(environment())
    print("Parent environment")
    print(parent.env(environment()))
    my_list$i <<- my_list$i + 1
  }
Run Code Online (Sandbox Code Playgroud)

它给了我:

> f$increment()
[1] "environment"
<environment: 0x0000000013c18538>
[1] "Parent environment"
<environment: 0x0000000022365d58>
Run Code Online (Sandbox Code Playgroud)

get存储环境名称后,您可以使用来访问您的结果:

> my_main_env <- environment(f$increment)
> get("my_list", env = my_main_env)
$i
[1] 2

$increment
function () 
{
    print("environment")
    print(environment())
    print("Parent environment")
    print(parent.env(environment()))
    my_list$i <<- my_list$i + 1
}
<environment: 0x0000000022365d58>

$get_i
function () 
{
    print("environment")
    print(environment())
    print("Parent environment")
    print(parent.env(environment()))
    my_list$i
}
<environment: 0x0000000022365d58>
Run Code Online (Sandbox Code Playgroud)