用于替换非本地列表中的值的赋值

时间:2015-07-17 12:54:57

标签: r list environment assign

在非本地对象上使用

[[<-对列表和环境的行为不同:

lst = list()
env = new.env()

(function () lst[['x']] = 1)()
(function () env[['x']] = 1)()
lst
# list()

as.list(env)
# $x
# [1] 1

换句话说,如果[[<-的目标是一个环境,它会修改(非本地)环境,但如果它是一个矢量/列表,它会创建一个新的本地对象。

我想知道两件事:

  1. 为什么会出现这种行为上的差异?
  2. 有没有办法为列表和环境实现相同的结果,没有使用<<-
  3. 关于(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必须做相当于:

    [[<-

1 个答案:

答案 0 :(得分:8)

R-language definition(第2.1.10节)说:

  

与大多数其他R对象不同,传递时不会复制环境   功能或用于作业。

“6.3评估的更多内容”部分也提供了一个略微相关的提示:

  

请注意,在给定环境中的评估可能实际上改变了这一点   环境,最明显的是涉及转让的案件   运算符,例如

eval(quote(total <- 0), environment(robert$balance)) # rob Rob
     

在列表中进行评估时也是如此,但原始列表确实如此   不要因为一个人正在制作副本而改变。

因此,您的第一个问题的答案是需要复制列表以进行分配,但可以对环境进行修改(这会产生巨大的性能影响)。

关于你的第二个问题:

如果您正在使用列表,唯一的选择似乎是

  • 将列表复制到本地范围(使用get),
  • 分配到列表中,
  • 使用assign将修改后的列表复制回原始环境。