c(1L,2L,3L)和1:3之间的修改时复制行为不同

时间:2019-04-16 17:23:11

标签: r

我正在阅读Hadley Wickham的Advanced R,试图解决第2.3.6节中有关修改时复制的exercise 2

  

解释为什么运行此代码时tracemem()显示两个副本。提示:请仔细查看此代码与本节前面显示的代码之间的区别。

     
x <- c(1L, 2L, 3L)
tracemem(x)

x[[3]] <- 4

(先前的代码将双精度列表中的一个元素更改为另一双精度,仅产生一个副本。)

在Grosser和Bumann的Advanced R Solutions they explain中,第二个副本归因于强制类型,从整数到双精度。它们没有将x定义为c(1L, 2L, 3L),而是使用了x <- 1:3,我认为这是等效的(使用identical进行比较也返回TRUE)。但是,运行上面的代码(最终)仅产生一个副本,但是运行下面的代码则产生两个副本:

x <- 1:3
tracemem(x)

x[[3]] <- 4

运行此代码还会产生两个副本:

x <- c(1L, 2L, 3L)
typeof(x)
tracemem(x)

x[[3]] <- 4

例如,将typeof替换为class仅产生一个副本,而将其替换为modepryr::otype则产生两个副本。但是只需打印出x即可得到一份副本。

那么c(1L, 2L, 3L)1:3之间有什么区别,为什么调用上面的一些但不是全部函数会改变行为呢?

我使用Rterm在RStudio的控制台中从PowerShell运行代码时,会得到相同的行为。

1 个答案:

答案 0 :(得分:0)

我在@brodieg的博客https://www.brodieg.com/2019/02/18/an-unofficial-reference-for-internal-inspect/#fn4中找到了答案

不使用tracemem,而是更深入地研究.Internal(inspect(x))

x <- c(1L, 6L, 10L)
.Internal(inspect(x))
#> @7fc0397e0f88 13 INTSXP g0c2 [NAM(1)] (len=3, tl=0) 1,6,10
x <- c(1L, 6L, 10L)
typeof(x)
.Internal(inspect(x))
#> @7fc0397e0f08 13 INTSXP g0c2 [NAM(7)] (len=3, tl=0) 1,6,10

.Internal(inspect(x))的返回值是一堆信息,但重要的是NAM。 NAM是参考计数器,是一种确定有多少R对象指向同一基础事物的方法。在这里typeof()使它递增。 typeof()是一个闭包,闭包的参数上的“ NAM”值始终递增。

在为元素分配新值时,并非总是会复制每个@brodieg x,但是当NAM引用计数启发式提示可能存在多个对象引用时。

我找不到关于引用和:的任何信息,但是使用它创建的对象的引用计数自动大于1

x <- 1:3
.Internal(inspect(x))
#> @7fc03bad6388 13 INTSXP g0c0 [NAM(7)]  1 : 3 (compact)

因此,对于带有x <- c(1L, 6L, 10L)的原始情况,引用计数仅为1,R启发式方法不会触发分配的副本,但会触发类型强制。这就是tracemem仅被触发一次的原因。