为什么长度为1的向量最初是在NAM(2)?

时间:2014-02-25 18:19:25

标签: r

我偶然发现了这种行为:

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上看到了这一点。

1 个答案:

答案 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=2x <- 1:10x <- 1:1x <- c(1)甚至x <- seq(1)不同的原因是RHS实际上是一个函数调用,该函数调用的结果是分配给x <- -1的结果。在这些情况下,x的值不仅仅是对其他符号值的引用;修改x不会改变某些其他符号的值,因此无需设置x