检查这个玩具代码:
> 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
Run Code Online (Sandbox Code Playgroud)
看来 data.table 是通过引用传递的。这是故意的吗?这有记录吗?我确实阅读了文档,但找不到提及此行为。
我并不是在询问 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>
Run Code Online (Sandbox Code Playgroud)
因此,不仅.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"
Run Code Online (Sandbox Code Playgroud)
也许根本问题是常规的 data.table 操作在某种程度上不会触发 R 的修改时复制语义?
我认为您感到惊讶的实际上是 R 行为,这就是为什么它没有在 中具体记录data.table(也许无论如何应该如此,因为其含义对于 更重要data.table)。
您会惊讶地发现传递给函数的对象具有相同的地址,但这对于baseR 来说也是相同的:
x = 1:10
address(x)
# [1] "0x7fb7d4b6c820"
(function(y) {print(address(y))})(x)
# [1] "0x7fb7d4b6c820"
Run Code Online (Sandbox Code Playgroud)
在函数环境中复制的是指向 的指针x。此外,对于baseR 来说,父级x是不可变的:
foo = function(y) {
print(address(y))
y[1L] = 2L
print(address(y))
}
foo(x)
# [1] "0x7fb7d4b6c820"
# [1] "0x7fb7d4e11d28"
Run Code Online (Sandbox Code Playgroud)
也就是说,一旦我们尝试编辑 y,就会创建一个副本。这与引用计数有关——你可以看到 Luke Tierney 在这方面的一些工作,例如这个演示文稿
不同之处在于data.table,它data.table 启用了父对象的编辑权限——我想您知道这是一把双刃剑。
| 归档时间: |
|
| 查看次数: |
819 次 |
| 最近记录: |