Метод "клонирования", опубликованный Томми, не сделает истинный (глубокий) клон, если e1
содержит имена, которые ссылаются на другие среды.Например, если e1$nestedEnv
ссылается на среду, e2$nestedEnv
будет ссылаться на ту же среду, а не на копию этой среды.Таким образом, имя e1$nestedEnv$bar
будет ссылаться на ту же ячейку памяти, что и e2$nestedEnv$bar
, и любое новое значение, присвоенное e1$nestedEnv$bar
, будет отражено и для e2$nestedEnv$bar
.Это может быть желательным поведением, но вызов e2
клона e1
может вводить в заблуждение.
Вот функция, которая позволит пользователю сделать либо копию среды, но и копировать любые вложенные среды.(«глубокий клон», используя deep = TRUE
), или просто используйте метод, предложенный Томми, для копирования среды, сохраняя при этом исходные ссылки на любые вложенные среды (используя deep = FALSE
).
The Deep =Метод TRUE использует rapply
для рекурсивного вызова cloneEnv
во вложенной среде в пределах envir
, для стольких уровней, сколько вложенная среда.Так что, в конце концов, он рекурсивно вызывает rapply
, что немного раздражает, но работает довольно хорошо.
Обратите внимание, что, если вложенная среда содержит имя, которое ссылается на родительскую среду, использование «глубокого» метода никогда не вернется из рекурсивных вызовов.Если бы я мог найти способ проверить это, я бы включил его ...
Обратите также внимание, что среды могут иметь атрибуты, поэтому копирование атрибутов будет необходимо для настоящего клона, которыйЭто решение также обращается к.
cloneEnv <- function(envir, deep = T) {
if(deep) {
clone <- list2env(rapply(as.list(envir, all.names = TRUE), cloneEnv, classes = "environment", how = "replace"), parent = parent.env(envir))
} else {
clone <- list2env(as.list(envir, all.names = TRUE), parent = parent.env(envir))
}
attributes(clone) <- attributes(envir)
return(clone)
}
Пример:
Создать среду e1
, которая также содержит вложенную среду:
e1 <- new.env()
e1$foo <- "Christmas"
e1$nestedEnv <- new.env()
e1$nestedEnv$bar <- "New Years"
Показать значения для foo
и bar
:
e1$foo
[1] "Christmas"
e1$nestedEnv$bar
[1] "New Years"
Сделать глубокий клон (т. Е. e2
содержит делает копию nestedEnv
)
e2 <- cloneEnv(e1, deep = TRUE)
nestedEnv
in e1
ссылается на среду, отличную от nestedEnv
в e2
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] FALSE
Но значения одинаковы, поскольку e2$nestedEnv
является копией e1$nestedEnv
:
e2$foo
[1] "Christmas"
e2$nestedEnv$bar
[1] "New Years"
Изменитьзначения в e2
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
И значения в e1
также остаются неизменными, поскольку e1$nestedEnv
указывает на среду, отличную от e2$nestedEnv
:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
e1$nestedEnv$bar
[1] "New Years"
e2$nestedEnv$bar
[1] "Thanksgiving"
Теперь заново создайте e1
, используя метод Томми:
e2 <- cloneEnv(e1, deep = FALSE)
nestedEnv
в e2
указывает на то же окружение, что и nestedEnv
в e1
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] TRUE
Обновите значения в e2
и e2
nestedEnv
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
Значения foo
являются независимыми:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
но при обновлении значения e2
bar
также обновлены e1
bar
, поскольку e1$nestedEnv
и e2$nestedEnv
ссылаются (указывают на) на одну и ту же среду.
e1$nestedEnv$bar
[1] "Thanksgiving"
e2$nestedEnv$bar
[1] "Thanksgiving"