我偶然发现了这种行为:
x <- 1:5
> tracemem(x)
[1] "<0x12145b7a8>"
> "names<-"(x, letters[1:5])
a b c d e
1 2 3 4 5
> x
a b c d e
1 2 3 4 5
> y <- 1L
> tracemem(y)
[1] "<0x12587ed68>"
> "names<-"(y,letters[1])
tracemem[0x12587ed68 -> 0x12587efa8]:
a
1
> y
[1] 1
在前一种情况下尝试帮助某人figure out why时,矢量的名称正在被修改,但在后者中则不是。
显然,正在复制一个向量的长度,而正在修改长度为5的向量:
> x <- 1:5
> y <- 1L
> .Internal(inspect(x))
@121467490 13 INTSXP g0c3 [MARK,NAM(1)] (len=5, tl=0) 1,2,3,4,5
> .Internal(inspect(y))
@1258d74d8 13 INTSXP g0c1 [NAM(2)] (len=1, tl=0) 1
为什么一个向量的长度开始存在,其NAMED属性递增为2?
回应下面的@nograpes评论,我在OS X 10.7.5和R 3.0.2上看到了这一点。
答案 0 :(得分:18)
Matthew Dowle问了同样的问题here,Peter Dalgaard这样回答:
这是一项棘手的业务......我不太确定我会做得对,但是 我们试试
分配常量时,已分配的值已经存在 分配表达式的一部分,所以如果你想修改它,你 必须复制。因此
NAMED==2
上的z <- 1
基本上是为了阻止您 意外地“改变1的价值”。如果不是,那么你可以 被for(i in 1:2) {z <- 1; if(i==1) z[1] <- 2}
等代码咬伤。
这可能看起来很奇特,但实际上,每当执行{{1>的分配时,其基本原理与将NAM
递增到2
的基本原理完全相同}}。
As discussed here,R支持“按值调用”错觉,以避免至少一些不必要的对象复制。因此,例如,x <- y
实际上只是将符号x <- y
绑定到x
的值。但是,如果没有进一步的预防措施,这样做的危险在于y
的后续修改也会修改x
以及与y
相关联的任何其他符号。 R通过将y
的值标记为“链接到”(通过将其设置为y
),一旦将其分配(或甚至可能分配)到另一个符号,就可以解决此问题。
当您执行NAM=2
时,x <- 1
或多或少只是另一个1
,其值通过赋值表达式链接到符号y
。只是因为随后修改x
的值而引起的恶作剧的可能性(回想起此时,它只是对x
的价值的参考!)可想而知。但是,与一个符号到另一个符号的分配一样,R设置1
,并且不允许在没有实际复制的情况下进行修改。
NAM=2
与x <- 1:10
,x <- 1:1
,x <- c(1)
甚至x <- seq(1)
不同的原因是RHS实际上是一个函数调用,该函数调用的结果是分配给x <- -1
的结果。在这些情况下,x
的值不仅仅是对其他符号值的引用;修改x
不会改变某些其他符号的值,因此无需设置x
。