将 function() 应用于 list() 和 new.env() 之间的区别?
Difference between applying a function() to list() and to new.env()?
为什么我打印 x$val 会得到两个不同的结果?我知道第一个是列表,第二个是环境,但我不明白是什么导致第二个块的 x$val 结果 = NA
x <- list()
x$val <- 1
myfun <- function(x) {x$val <- x$val + NA}
myfun(x)
x$val
##[1] 1
x <- new.env()
x$val <- 18
myfun <- function(x) {x$val <- x$val + NA}
myfun(x)
x$val
##[1] NA
环境是 R 中的“引用对象”。这意味着如果您将一个变量分配给一个新变量,则对任一副本的更改都会影响两个副本。列表与大多数其他对象一样,并在分配时被复制。
因此,在您的第一个示例中,myfun(x)
制作了列表 x
的单独副本,并在函数中对其进行处理。对全局变量x
.
没有影响
在您的第二个示例中,myfun(x)
对环境 x
进行了新引用,并在函数中对其进行处理。这也会影响原始变量。
好的,基于使用 <<-
一些示例的风险的合法评论。
有风险的解决方案
x <- list("val" = 1L)
myfun <- function(x) {x$val <<- x$val + NA}
myfun(x)
x
# $val
# [1] NA
有风险的解决方案大错特错
x <- list("val" = "Please do not alter me at all")
y <- list("val" = 1L)
myfun <- function(x) {x$val <<- x$val + NA}
myfun(y)
x
# $val
# [1] NA
y
# $val
# [1] 1
让你的函数输出你的数据
x <- list("val" = 1L)
myfun <- function(x) list("val" = x$val + NA)
x <- myfun(x)
x
# $val
# [1] NA
使用环境
y <- new.env()
y$val <- 18L
myfun <- function(x) {x$val <- x$val + NA}
myfun(y)
y$val
# [1] NA
这里有几个问题:
Return value 函数 returns 最后执行的语句的值,在本例中是 [= 的两个实例12=] return x$val
即 NA
(将 NA 添加到任何数字得到 NA)所以它们 return 相同的值。
修改时复制 如果在函数中修改了诸如 x
的对象,则该函数会创建该对象的副本,然后修改复制。函数外的原始对象没有改变。
对象标识环境的标识独立于它们的内容,因此改变环境的内容不会改变环境本身的标识——它只是更改内容。因此,更改环境的内容不会导致在函数内复制环境。 (这类似于 C 中的指针,其中程序可以修改指向的数据而不修改指针本身。)另一方面,列表没有与其内容不同的标识。在函数中修改列表的内容会导致将列表复制到新列表,然后修改新列表。
例子
下面,我们使用pryr中的address
来跟踪列表的地址。对于环境,简单地打印环境将显示其地址,因此我们不需要它。下面的跟踪语句导致 R 在进入和退出时显示地址。
列表的地址在进入函数之前和进入时是...968,但在函数内修改它之后,它已成为位于新地址...200 的新列表,这是函数的本地地址,并且与仍在地址 ...968 的函数外部列表不同。
library(pryr)
x <- list()
x$val <- 1
myfun_env <- function(x) {x$val <- x$val + NA}
trace(myfun_list, tracer = quote(print(address(x))), exit = quote(print(address(x))))
## [1] "myfun_list"
address(x)
## [1] "000000000bbbb968"
myfun_list(x)
## Tracing myfun_list(x) on entry
## [1] "000000000bbbb968"
## Tracing myfun_list(x) on exit
## [1] "000000000b368200"
## [1] NA
address(x)
## [1] "000000000bbbb968"
另一方面,在环境的情况下,它具有与其内容不同的身份,因此更改内容不会导致将环境复制到新环境。环境从 ...238 开始,并且在整个代码中永远不会改变。
x <- new.env()
x$val <- 18
myfun_env <- function(x) {x$val <- x$val + NA}
trace(myfun_env, tracer = quote(print(x)), exit = quote(print(x)))
## [1] "myfun_env"
x
## <environment: 0x000000000cac4238>
myfun_env(x)
## Tracing myfun_env(x) on entry
## <environment: 0x000000000cac4238>
## Tracing myfun_env(x) on exit
## <environment: 0x000000000cac4238>
x
## <environment: 0x000000000cac4238>
为什么我打印 x$val 会得到两个不同的结果?我知道第一个是列表,第二个是环境,但我不明白是什么导致第二个块的 x$val 结果 = NA
x <- list()
x$val <- 1
myfun <- function(x) {x$val <- x$val + NA}
myfun(x)
x$val
##[1] 1
x <- new.env()
x$val <- 18
myfun <- function(x) {x$val <- x$val + NA}
myfun(x)
x$val
##[1] NA
环境是 R 中的“引用对象”。这意味着如果您将一个变量分配给一个新变量,则对任一副本的更改都会影响两个副本。列表与大多数其他对象一样,并在分配时被复制。
因此,在您的第一个示例中,myfun(x)
制作了列表 x
的单独副本,并在函数中对其进行处理。对全局变量x
.
在您的第二个示例中,myfun(x)
对环境 x
进行了新引用,并在函数中对其进行处理。这也会影响原始变量。
好的,基于使用 <<-
一些示例的风险的合法评论。
有风险的解决方案
x <- list("val" = 1L)
myfun <- function(x) {x$val <<- x$val + NA}
myfun(x)
x
# $val
# [1] NA
有风险的解决方案大错特错
x <- list("val" = "Please do not alter me at all")
y <- list("val" = 1L)
myfun <- function(x) {x$val <<- x$val + NA}
myfun(y)
x
# $val
# [1] NA
y
# $val
# [1] 1
让你的函数输出你的数据
x <- list("val" = 1L)
myfun <- function(x) list("val" = x$val + NA)
x <- myfun(x)
x
# $val
# [1] NA
使用环境
y <- new.env()
y$val <- 18L
myfun <- function(x) {x$val <- x$val + NA}
myfun(y)
y$val
# [1] NA
这里有几个问题:
Return value 函数 returns 最后执行的语句的值,在本例中是 [= 的两个实例12=] return
x$val
即NA
(将 NA 添加到任何数字得到 NA)所以它们 return 相同的值。修改时复制 如果在函数中修改了诸如
x
的对象,则该函数会创建该对象的副本,然后修改复制。函数外的原始对象没有改变。对象标识环境的标识独立于它们的内容,因此改变环境的内容不会改变环境本身的标识——它只是更改内容。因此,更改环境的内容不会导致在函数内复制环境。 (这类似于 C 中的指针,其中程序可以修改指向的数据而不修改指针本身。)另一方面,列表没有与其内容不同的标识。在函数中修改列表的内容会导致将列表复制到新列表,然后修改新列表。
例子
下面,我们使用pryr中的address
来跟踪列表的地址。对于环境,简单地打印环境将显示其地址,因此我们不需要它。下面的跟踪语句导致 R 在进入和退出时显示地址。
列表的地址在进入函数之前和进入时是...968,但在函数内修改它之后,它已成为位于新地址...200 的新列表,这是函数的本地地址,并且与仍在地址 ...968 的函数外部列表不同。
library(pryr)
x <- list()
x$val <- 1
myfun_env <- function(x) {x$val <- x$val + NA}
trace(myfun_list, tracer = quote(print(address(x))), exit = quote(print(address(x))))
## [1] "myfun_list"
address(x)
## [1] "000000000bbbb968"
myfun_list(x)
## Tracing myfun_list(x) on entry
## [1] "000000000bbbb968"
## Tracing myfun_list(x) on exit
## [1] "000000000b368200"
## [1] NA
address(x)
## [1] "000000000bbbb968"
另一方面,在环境的情况下,它具有与其内容不同的身份,因此更改内容不会导致将环境复制到新环境。环境从 ...238 开始,并且在整个代码中永远不会改变。
x <- new.env()
x$val <- 18
myfun_env <- function(x) {x$val <- x$val + NA}
trace(myfun_env, tracer = quote(print(x)), exit = quote(print(x)))
## [1] "myfun_env"
x
## <environment: 0x000000000cac4238>
myfun_env(x)
## Tracing myfun_env(x) on entry
## <environment: 0x000000000cac4238>
## Tracing myfun_env(x) on exit
## <environment: 0x000000000cac4238>
x
## <environment: 0x000000000cac4238>