Почему г не модифицирует место в этой ситуации? - PullRequest
2 голосов
/ 15 марта 2020
> z <- 1:10
> lobstr::obj_addr(z)
[1] "0x564d8d9eaac8"

> z[[3]] <- 4L
> lobstr::obj_addr(z)
[1] "0x564d882b4328"

Почему адрес меняется после модификации? Это должна быть модификация на месте, нет?

1 Ответ

3 голосов
/ 15 марта 2020

Более ранние вопросы (например, здесь ) объясняют некоторые аспекты того, когда R выполняет копию. Однако в примере OP есть еще один нюанс, который стоит подчеркнуть здесь. Обратите внимание, что следующий код был выполнен в консоли R, а не в RStudio. Как уже отмечали другие ранее , Rstudio имеет свои собственные воздействия на процесс, которые мы здесь исключаем, работая непосредственно в R.

R "копия при изменении поведения" может быть сложной. R попытается провести замену на месте, по возможности . Но есть интересная причина, что это не одна из тех ситуаций, где это можно сделать. Это связано с оптимизацией «AltRep» (альтернативное представление), введенной начиная с версии 3.5.0. Одной из таких оптимизаций является возможность хранить смежные последовательности чисел, используя только их конечные элементы, а не выделять весь вектор. См. здесь для более подробной информации.

Давайте попробуем посмотреть, что происходит в этом случае, используя .Internal(inspect(z)), чтобы увидеть внутреннее представление объекта, и tracemem, чтобы определить, когда объект был скопирован:

x = 1L:10L
tracemem(x)
# [1] "<0x559377dba830>"
.Internal(inspect(x))
# @559377dba830 13 INTSXP g0c0 [NAM(7),TR]  1 : 10 (compact)

Как мы видим, на этом этапе 1:10 представлен в виде 1:10 (компактный). Это означает, что полная последовательность еще не была явно оценена или распределена. Пока существует только компактное представление его начальных и конечных значений.

Теперь, когда мы присваиваем элементу вектора, мы видим, что объект копируется:

x[[3]] = 4L
# tracemem[0x559377dba830 -> 0x559376ae1e48]: 

И мы также можем видеть, что внутренности объекта также были заменены явным вектором целых чисел, а не 1:10 «компактной» формой:

.Internal(inspect(x))
# @559376ae1e48 13 INTSXP g0c4 [NAM(1),TR] (len=10, tl=0) 1,2,4,4,5,...

Теперь сравните это со следующей версией, в которой копия не запускается (поскольку исходный вектор уже был в развернутом (не компактном) виде):

x = c(1L:10L)
tracemem(x)
# [1] "<0x55d6146772d8>"
.Internal(inspect(x))
# @55d6146772d8 13 INTSXP g0c4 [NAM(1),TR] (len=10, tl=0) 1,2,3,4,5,...

x[[3]] = 4L
# No copying occured here!!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...