R中的复制-修改语义到底是什么,规范源在哪里?

R中的复制-修改语义到底是什么,规范源在哪里?,r,pass-by-reference,pass-by-value,R,Pass By Reference,Pass By Value,每隔一段时间,我就会遇到这样一个概念,即R具有修改时复制语义,例如在中 大多数R对象都具有copy-on-modify语义,因此修改函数 参数不会更改原始值 我可以将这个术语追溯到R-Help邮件列表。例如,Peter Dalgaard写道: R是一种函数式语言,具有惰性计算和弱动态性 键入(变量可以随意更改类型:按值调用 报告(在第节中)这样说 在R参数中调用函数的语义是按值调用。通常,提供的参数的行为就像是使用提供的值和相应形式参数的名称初始化的局部变量一样。在函数中更改提供的参数的值不会影

每隔一段时间,我就会遇到这样一个概念,即R具有修改时复制语义,例如在中

大多数R对象都具有copy-on-modify语义,因此修改函数 参数不会更改原始值

我可以将这个术语追溯到R-Help邮件列表。例如,Peter Dalgaard写道:

R是一种函数式语言,具有惰性计算和弱动态性 键入(变量可以随意更改类型:按值调用 报告(在第节中)这样说

在R参数中调用函数的语义是按值调用。通常,提供的参数的行为就像是使用提供的值和相应形式参数的名称初始化的局部变量一样。在函数中更改提供的参数的值不会影响va的值调用帧中的变量[添加了强调]

虽然这没有描述修改时复制的机制,但它确实提到更改传递给函数的对象不会影响调用帧中的原始对象

更多信息,特别是关于修改时复制方面的信息,请参见第节中的
SEXP
s的说明。具体说明[重点已添加]

named
字段由
set\u named
named
宏,并获取值
0
1
2
。R具有“按值调用” 幻觉,像这样的任务

b <- a
原则上,合同有效期内存在两份副本 计算为(原则上)


a我对它做了一些实验,发现R总是在第一次修改时复制对象

你可以在我的机器上看到结果

如果我犯了什么错误,请告诉我,谢谢


测试是否复制了对象的步骤 我使用以下C代码转储内存地址:

#define USE_RINTERNALS
#include <R.h>
#include <Rdefines.h>

SEXP dump_address(SEXP src) {
  Rprintf("%16p %16p %d\n", &(src->u), INTEGER(src), INTEGER(src) - (int*)&(src->u));
  return R_NilValue;
}
会话信息 下面是测试环境的
sessionInfo

sessionInfo()
抄写 首先我测试了写时复制的属性, 这意味着R仅在对象被修改时复制对象

a <- 1L
b <- a
invisible(.Call("dump_address", a))
invisible(.Call("dump_address", b))
b <- b + 1
invisible(.Call("dump_address", b))
地址每次都会更改,这意味着R不会重用内存

长向量
system.time(a在某些情况下,为了给开发人员改变其工作方式的余地,内部可能不会被记录。在这种情况下,不应该编写依赖于内部操作的代码,因为它可能在将来中断。重要的一点(应该强调)是R打来的吗-value@hadley但是,
命名的
概念是否也用于函数调用,以及额外的承诺问题?@hadley增加了新的重点。命名只是一种优化。没有它,R的行为会完全相同。非常正确@JoshO'Brien+1。我在那里用了太多的措辞,改变了Peter所写内容的意图。将相应地进行编辑。+1.非常有趣。我想您可以发布一个问题,关于R为什么在第一次修改/属性设置时复制对象。
Rcpp:::SHLIB("dump_address.c")
dyn.load("dump_address.so")
sessionInfo()
a <- 1L
b <- a
invisible(.Call("dump_address", a))
invisible(.Call("dump_address", b))
b <- b + 1
invisible(.Call("dump_address", b))
a <- 1L
invisible(.Call("dump_address", a))
a <- 1L
invisible(.Call("dump_address", a))
a[1] <- 1L
invisible(.Call("dump_address", a))
a <- 2L 
invisible(.Call("dump_address", a))
system.time(a <- rep(1L, 10^7))
invisible(.Call("dump_address", a))
system.time(a[1] <- 1L)
invisible(.Call("dump_address", a))
system.time(a[1] <- 1L)
invisible(.Call("dump_address", a))
system.time(a[1] <- 2L)
invisible(.Call("dump_address", a))
system.time(a <- matrix(0L, 3162, 3162))
invisible(.Call("dump_address", a))
system.time(a[1,1] <- 0L)
invisible(.Call("dump_address", a))
system.time(a[1,1] <- 1L)
invisible(.Call("dump_address", a))
system.time(a[1] <- 2L)
invisible(.Call("dump_address", a))
system.time(a[1] <- 2L)
invisible(.Call("dump_address", a))
system.time(a <- vector("integer", 10^2))
invisible(.Call("dump_address", a))
system.time(names(a) <- paste(1:(10^2)))
invisible(.Call("dump_address", a))
system.time(names(a) <- paste(1:(10^2)))
invisible(.Call("dump_address", a))
system.time(names(a) <- paste(1:(10^2) + 1))
invisible(.Call("dump_address", a))