R,深拷贝和浅拷贝,通过引用传递

时间:2012-05-18 15:17:18

标签: r reference copy deep-copy data.table

我想理解R在向函数传递参数时使用的逻辑,创建关于内存使用的变量副本等。它什么时候实际创建变量的副本而不是仅仅传递对该变量的引用?特别是我很好奇的情况是:

f <- function(x) {x+1}
a <- 1
f(a)

a是按字面顺序传递还是引用被传递?

x <- 1
y <- x

副本的参考?什么时候不是这样?

如果有人能向我解释这一点,我将非常感谢。

3 个答案:

答案 0 :(得分:14)

当它传递变量时,它总是通过复制而不是通过引用。但是,有时候,在实际发生任务之前,您不会获得副本。该过程的真实描述是传承承诺。看一下文档

?force
?delayedAssign

一个实际意义是,即使不是不可能,也很难避免需要至少两倍于名义上占据的对象的RAM。修改大对象通常需要制作临时副本。

更新:2015:我确实(并且确实)同意Matt Dowle他的data.table包提供了另一种分配路径,可以避免复制 - 重复问题。如果那是要求的更新,那么在提出建议时我并不理解。

最近,applyReduce的评估规则对R 3.2.1进行了更改。在这里参考了新闻,宣布了这一点:Returning anonymous functions from lapply - what is going wrong?

interesting paper cited by jhetzel in the comments is now here

答案 1 :(得分:0)

最新答案只是语言设计的一个非常重要的方面,它在网络上(或至少是通常的来源)没有得到足够的报道。

x <- c(0,4,2)
lobstr::obj_addr(x)
# [1] "0x7ff25e82b0f8"
y <- x
lobstr::obj_addr(y)
# [1] "0x7ff25e82b0f8"

请注意相同的“内存地址”,即对象在内存中的存储位置。因此,您可以确认xy都指向相同的标识符。

哈德利·威克汉姆(Hadley Wickham)的Advanced R书对此进行了润饰:

  

考虑此代码

     

x <- c(1, 2, 3)

     

易于理解为:“创建一个名为“ x”的对象,   包含值1、2和3”。不幸的是   简化将导致关于R的错误预测   实际上是在幕后做的。说的更准确   该代码可做两件事:

     

它正在创建一个对象,值的向量,c(1, 2, 3)。这是   将该对象绑定到名称x。换句话说,对象,或   值,没有名字;它实际上是具有值的名称。

请注意,它们是临时性的内存地址,并且在每个新的R会话中都会更改。

现在这是重要的部分。

  

在R语义中,对象是按值复制的。这意味着修改   副本使原始对象保持原样。由于复制数据在   内存是一项昂贵的操作,R中的副本尽可能懒。   它们仅在实际修改了新对象时发生。   来源:[R lang文档] [1]

因此,如果我们现在通过将值附加到向量来修改y的值,则y现在指向另一个“对象”。这与文档中有关“仅在修改新对象时”发生的复制操作有关(懒惰的)一致。 y指向的地址与以前不同。

y <- c(y, -3)
print(lobstr::obj_addr(y))
# [1] "0x7ff25e825b48"

答案 2 :(得分:0)

@onlyphantom超级有用!对象可以在不复制的情况下往返于函数之外:这就是让我来到这里的原因:

tmp <- function(x, create) {
    if(!create){
        x
    }else{
        "new"
    }
}

x = c(0,4,2)

y = tmp(x, F)
lobstr::obj_addr(x) == lobstr::obj_addr(y) # y points to x!

并且当用其自身“替换” x时,此方法有效-无副本!

oldAddr = lobstr::obj_addr(x) 
x = tmp(x, F)
lobstr::obj_addr(x) == oldAddr # TRUE!

手册中的此示例(稍作修改)还有助于触发惰性评估

tmp = function(x, label = deparse(x), force=TRUE) {
    if(force){
        label
    }
    x <- x + 1
    print(label); return(x)
}
tmp(2)
[1] "2"
[1] 3

tmp(2, force=F)
[1] "3"
[1] 3

R版本3.6.3