[[<-
对列表和环境的行为不同:
lst = list()
env = new.env()
(function () lst[['x']] = 1)()
(function () env[['x']] = 1)()
lst
# list()
as.list(env)
# $x
# [1] 1
换句话说,如果[[<-
的目标是一个环境,它会修改(非本地)环境,但如果它是一个矢量/列表,它会创建一个新的本地对象。
我想知道两件事:
<<-
? 关于(1),我知道列表和环境之间存在多种差异(特别是,我知道环境不会被复制)但文档中没有提到为什么语义为[[<-
两者之间存在差异 - 尤其是运营商为何在不同范围内运营。这是一个错误吗?它至少是反直觉的,需要一些非平凡的实现诡计。 1
关于(2),显而易见的解决方案当然是使用<<-
:
(function () lst[['x']] <<- 1)()
但是,我更倾向于严格理解差异而不是仅仅解决它们。此外,我到目前为止使用的是assign
而不是<<-
,我更喜欢这个,因为它允许我更好地控制赋值的范围(特别是因为我可以指定inherits = FALSE
。根据我的口味<<-
太多巫术了。
但是,使用assign
无法解决上述问题(据我所知),因为assign
仅适用于环境,而不适用于列表。特别是,虽然assign('x', 1, env)
有效(并且与上面相同),但assign('x', 1, lst)
不起作用。
1
详细说来,当然希望R使用动态调度(例如通过S3)对不同的对象类型做不同的事情。但是,这里的情况 not (至少不是直接):范围解析的区别发生在分配目标的对象类型已知之前 - 否则上述操作将在全局{{1而不是创建一个新的本地对象。所以内部lst
必须做相当于:
[[<-
答案 0 :(得分:8)
R-language definition(第2.1.10节)说:
与大多数其他R对象不同,传递时不会复制环境 功能或用于作业。
“6.3评估的更多内容”部分也提供了一个略微相关的提示:
请注意,在给定环境中的评估可能实际上改变了这一点 环境,最明显的是涉及转让的案件 运算符,例如
eval(quote(total <- 0), environment(robert$balance)) # rob Rob
在列表中进行评估时也是如此,但原始列表确实如此 不要因为一个人正在制作副本而改变。
因此,您的第一个问题的答案是需要复制列表以进行分配,但可以对环境进行修改(这会产生巨大的性能影响)。
关于你的第二个问题:
如果您正在使用列表,唯一的选择似乎是
get
),assign
将修改后的列表复制回原始环境。