我对"高级R"(https://adv-r.hadley.nz/names-values.html)第3.36节中的问题4感到有些困惑.我链接的章节解释了我在附加的图像中使用的约定.我将简要总结一下.对于那些不熟悉本书的人以及那些不想点击链接并阅读作者关于类似于我的图表描述的人,我添加了一个简短的解释,我在图像中使用的约定低于其余部分.这个帖子.
运行此代码会发生什么?画一张图
x <- list(1:10)
x[[2]] <- x
Run Code Online (Sandbox Code Playgroud)
我理解这里创造的是什么.x <- list(1:10)创建一个列表.该列表有一个指向向量1:10的元素.之后x[[2]] <- x运行,X点有两个元素的列表.第一个元素指向矢量1:10.第二个元素是对与原始列表相同的列表的引用(或者它可能不仅与原始列表相同,但实际上是原始列表?).我只是对在新列表中复制和/或引用哪些对象(不是变量,对象)感到困惑.
这是尝试解决方案.
刚运行后x <- list(1:10),名称x绑定到列表对象.该列表有一个引用,即向量(1:10).

这是我困惑的地方.我不确定x[[2]] <- x执行时会发生什么.这是我最好的猜测,我认为这是错误的.当x[[2]] <- x被执行时,使得x的对象的副本最初结合到制成.对于该副本,将创建指向原始对象的第二个元素.
我假设我对x[[2]] <- x执行不正确时会发生什么的解释.如果是这样,有人可以帮我理解发生了什么吗?如果我碰巧是正确的,有人可以帮助解释我为什么是正确的吗?
在我使用的图像中,圆角正方形表示名称/变量.黑色箭头是从名称到对象的绑定(与赋值箭头指向R的方向相反).下面的矩形表示内部有绿色圆圈时的列表.绿色圆圈表示列表的元素.由于列表元素是对象的引用,因此绿色箭头指向列表元素引用的对象.
在第一个图像中,列表有一个元素,该元素指向矢量1:10.
在第二个图像中,列表对象的第一个元素指向向量1:10.第二个元素是对列表的引用.
也许这会有所帮助.这里我们pryr::address用来查看存储对象的内存位置(注意,您的实际地址可能会有所不同,但是当我有匹配的地址时,您的地址也应该匹配).
library(pryr)
x <- list(1:10)
pryr::address(x)
# [1] "0x3452810"
y <- x[[1]]
pryr::address(y)
# [1] "0x16b53bf0"
Run Code Online (Sandbox Code Playgroud)
所以我们x在给定的位置有一个列表.我们可以将R中的列表视为指向其他对象的指针的集合.我们不能直接获取它存储它的第一个项目的地址(至少,我不知道如何address),但我们可以存储该值y,因为R只会在修改对象时更改地址,我们可以假设这是第一个值存储的位置.现在让我们更新x
x[[2]] <- x
pryr::address(x)
# [1] "0x16001018"
Run Code Online (Sandbox Code Playgroud)
我们可以看到它x已经改变并被赋予了新的内存位置
y <- x[[1]]
pryr::address(y)
# [1] "0x16b53bf0"
Run Code Online (Sandbox Code Playgroud)
请注意,第一个元素仍然在同一个内存地址.所以还没有制作这个载体的新副本.新列表只指向同一个向量.现在让我们看一下我们刚刚添加的值的地址
y <- x[[2]]
pryr::address(y)
# [1] "0x3452810"
Run Code Online (Sandbox Code Playgroud)
请注意,此值现在指向原始所在的旧内存地址x.
还有更多
y <- x[[2]][[1]]
pryr::address(y)
# [1] "0x16b53bf0"
Run Code Online (Sandbox Code Playgroud)
两个列表都指向相同的1:10向量.它只存储一次.
因此,当您执行的操作x[[2]]<-x是创建新列表时.这个新列表基本上包含两个"指针".一个到原始列表中的相同向量,一个指向列表的原始地址.