This is covered in Hadley's Advanced R book. In it he says (paraphrasing here) that whenever 2 or more variables point to the same object, R will make a copy and then modify that copy. Before going into examples, one important note which is also mentioned in Hadley's book is that when you're using RStudio
the environment browser makes a reference to every object you create on the command line.
Given your observed behavior, I'm assuming you're using RStudio
which we will see will explain why there are actually 2 variables pointing to a
instead of 1 like you might expect.
The function we'll use to check how many variables are pointing to an object is refs()
. In the first example you posted you can see:
library(pryr)
a = 1:10
refs(x)
#[1] 2
This suggests (which is what you found) that 2 variables are pointing to a
and thus any modification to a
will result in R copying it, then modifying that copy.
Checking the for loop
we can see that y
always has the same address and that refs(y) = 1
in the for loop. y
is not copied because there are no other references pointing to y
in your function y[i] = x[i] - x[i-1]
:
for(i in 2:length(x))
{
y[i] = x[i] - x[i-1]
print(c(address(y), refs(y)))
}
#[1] "0x19c3a230" "1"
#[1] "0x19c3a230" "1"
#[1] "0x19c3a230" "1"
#[1] "0x19c3a230" "1"
#[1] "0x19c3a230" "1"
#[1] "0x19c3a230" "1"
#[1] "0x19c3a230" "1"
#[1] "0x19c3a230" "1"
#[1] "0x19c3a230" "1"
On the other hand if introduce a non-primitive function of y
in your for loop
you would see that address of y
changes each time which is more in line with what we would expect:
is.primitive(lag)
#[1] FALSE
for(i in 2:length(x))
{
y[i] = lag(y)[i]
print(c(address(y), refs(y)))
}
#[1] "0x19b31600" "1"
#[1] "0x19b31948" "1"
#[1] "0x19b2f4a8" "1"
#[1] "0x19b2d2f8" "1"
#[1] "0x19b299d0" "1"
#[1] "0x19b1bf58" "1"
#[1] "0x19ae2370" "1"
#[1] "0x19a649e8" "1"
#[1] "0x198cccf0" "1"
Note the emphasis on non-primitive. If your function of y
is primitive such as -
like: y[i] = y[i] - y[i-1]
R can optimize this to avoid copying.
Credit to @duckmayr for helping explain the behavior inside the for loop.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…