R data.table 是否记录为通过引用作为参数传递?

2024-03-21

检查这个玩具代码:

> x <- data.table(a = 1:2) 
> foo <- function(z) { z[, b:=3:4]  }
> y <- foo(x)
> x[]
   a b
1: 1 3
2: 2 4

看来 data.table 是通过引用传递的。这是故意的吗?这有记录吗?我确实阅读了文档,但找不到提及此行为。

I'm not询问 R 记录的参考语义(在:=, set***和其他一些)。我问 data.table 完整对象是否应该作为函数参数通过引用传递。


编辑:根据@Oliver 的回答,这里有一些更奇怪的例子。

> dt<- data.table(a=1:2)
> attr(dt, ".internal.selfref")
<pointer: 0x564776a93e88>
> address(dt)
[1] "0x5647bc0f6c50"
> 
> ff<-function(x) { x[, b:=3:4]; print(address(x)); print(attr(dt, ".internal.selfref")) }
> ff(dt)
[1] "0x5647bc0f6c50"
<pointer: 0x564776a93e88>

所以不仅是.internal.selfref与调用者的 dt 副本相同,地址也是如此。这确实是同一个物体。 (我认为)。

data.frames 的情况并非如此:

> df<- data.frame(a=1:2)
> address(df)
[1] "0x5647b39d21e8"
> ff<-function(x) { print(address(x)); x$b=3:4; print(address(x)) }
> 
> ff(df)
[1] "0x5647b39d21e8"
[1] "0x5647ae24de78"

也许根本问题是常规的 data.table 操作在某种程度上不会触发 R 的修改时复制语义?


我认为你感到惊讶的实际上是 R 行为,这就是为什么它没有具体记录在data.table(也许无论如何都应该如此,因为这对于data.table).

您对传递给函数的对象具有相同的地址感到惊讶,但这对于baseR 也是:

x = 1:10
address(x)
# [1] "0x7fb7d4b6c820"
(function(y) {print(address(y))})(x)
# [1] "0x7fb7d4b6c820"

正在发生什么copied在函数环境中是pointer to x。此外,对于baseR,父级x是不可变的:

foo = function(y) {
  print(address(y))
  y[1L] = 2L
  print(address(y))
}
foo(x)
# [1] "0x7fb7d4b6c820"
# [1] "0x7fb7d4e11d28"

也就是说,只要我们尝试edit y,复制一份。这与引用计数——你可以看到卢克·蒂尔尼(Luke Tierney)在这方面的一些工作,例如这个演示文稿 https://homepage.divms.uiowa.edu/%7Eluke/talks/dsc2014.pdf

差异为data.table就是它data.table 启用父对象的编辑权限——我想你知道这是一把双刃剑。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

R data.table 是否记录为通过引用作为参数传递? 的相关文章

随机推荐