首页 > 解决方案 > R data.table 是否记录为通过引用作为参数传递?

问题描述

检查这个玩具代码:

> 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 是通过引用传递的。这是故意的吗?这有记录吗?我确实通读了文档,但找不到关于这种行为的提及。

不是在询问 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 的 copy-on-modify 语义?

标签: rdata.table

解决方案


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

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

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

在函数环境中复制指向. x此外,对于baseR,父x级是不可变的:

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

也就是说,只要我们尝试编辑 y,就会制作一份副本。这与引用计数有关——你可以看到 Luke Tierney 在这方面的一些工作,例如这个演示文稿

不同之data.table处在于它data.table 启用了父对象的编辑权限——我想你知道这是一把双刃剑。


推荐阅读