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

jor*_*ran 18 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 
Run Code Online (Sandbox Code Playgroud)

当试图帮助某人弄清楚 为什么在前一种情况下,矢量的名称正在被修改,但在后一种情况下它们不是.

显然,正在复制一个向量的长度,而长度为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
Run Code Online (Sandbox Code Playgroud)

为什么长度为一的向量开始存在,其NAMED属性增加到2?

为了回应下面的@nograpes评论,我在OS X 10.7.5和R 3.0.2上看到了这一点.

Jos*_*ien 18

Matthew Dowle在这里问了同样的问题,而Peter Dalgaard也这样回答:

这是一件棘手的事情......我不太确定我会做对,但试试吧

分配常量时,分配的值已经是赋值表达式的一部分,因此如果要修改它,则必须复制.因此,NAMED==2z <- 1基本上以防止意外"变化值1".如果不是,那么你可能会受到类似代码的攻击for(i in 1:2) {z <- 1; if(i==1) z[1] <- 2}.

这可能看起来很奇特,但实际上,基本原理NAM2 每次进行表单赋值时的增量完全相同x <- y.

如此处所讨论的,R支持"按值调用"错觉以避免至少一些不必要的对象复制.所以,例如,x <- y真的只是将符号绑定x到它y的价值.但是,如果没有进一步的预防措施,这样做的危险在于随后的修改x也会修改y和链接的任何其他符号y.R y通过将其值标记为"链接到"(通过设置它NAM=2)一旦被分配(或甚至可能被分配)到另一个符号,就可以解决这个问题.

当你这样做时x <- 1,1或多或少只是另一个,y其值x通过赋值表达式链接到符号.只是,从后续的修改产生了恶作剧的潜在x的价值(提醒的是,在这一点上,它只是价值的参考1!)是可怕的想象.但是,一如既往地将一个符号分配给另一个符号,R设置NAM=2,并且不允许在没有实际复制的情况下进行修改.

究其原因x <- 1:10是不同的(因为是x <- 1:1,x <- c(1),x <- seq(1),甚至x <- -1)是在RHS实际上是一个函数调用,而函数调用的结果是什么东西被分配到x.在这些情况下,值x不仅仅是对某个其他符号的值的引用; 修改x不会潜在地改变某些其他符号的值,因此不需要设置NAM=2.

  • 彼得建议如果没有这个,`z [1] < - 2`实际上可以将`1`的值改为'2'吗?因为循环中的第一个赋值,`1`与`z`密切相关? (2认同)
  • @GavinSimpson是的.我将对我的答案进行编辑,旨在澄清这一点并回答joran的查询. (2认同)