3

我有一个用例将函数映射到向量,然后将结果分配给父环境中的各个对象——不是全局环境,而是map()调用它的环境。具体来说,这一切都发生在一个函数中,所以我想将这些对象分配给函数的环境,以便在函数调用中进行后续使用,并且只在函数调用中使用。

我知道您可以通过升序数字位置(全局为 1)或通过从当前环境倒数来指定环境,即使用rlang::caller_env(). 但是,无论哪种方法,在这种情况下,我都没有可靠的方法来指定所需的函数执行环境。正如下面的代表所示,我可以让它在一个特定的情况下工作rlang::caller_env(6),但很明显,在这种情况下,正好计数 6 帧恰好在这种情况下工作,它具有特定的管道链和操作序列,并且任何情况都可能有任何那里需要的其他值 - 通过在函数中打印回溯,我只发现 6 是正确的数字。使用map()时,是 13 什么的,可能是因为里面的所有嵌套函数调用map(). 而且我根本无法使用它list2env()

所以我正在寻找的是一些我可以提供的参数,list2env()或者assign()将清楚一致地导致分配特别发生在我正在使用它们的函数的环境中,即使我在最后调用这些函数的管道链。


library(tidyverse)
library(rlang, warn.conflicts = FALSE)

## Trying to assign the value 'foo' to an object named 'bar' in a specific
## location

# Fails because `bar` is assigned in the pipe execution evironment
'foo' %>% assign(x = 'bar')
exists('bar')
#> [1] FALSE

# Works because `pos = 1` refers specifically to the global environment
'foo' %>% assign(x = 'bar', pos = 1)
exists('bar')
#> [1] TRUE
rm(bar)

# Works because assign isn't in a pipe, and its special, default `pos` of
# `-1` refers to the function execution environment, as desired
exec(function() {
  assign('bar', 'foo')
  exists('bar', inherits = FALSE)
})
#> [1] TRUE
rm(bar)
#> Warning in rm(bar): object 'bar' not found

# Fails because the function's exec. env. is "overshot," and the assignment
# occurs in the global environment instead; no numeric position seems to work
exec(function() {
  'foo' %>% assign(x = 'bar', pos = 1)
  exists('bar', inherits = FALSE)
})
#> [1] FALSE
rm(bar)

# Works, presumably because the function's exec. env. happens to be exactly 6
# frames back from the environment in which the `assign()` call is evaluated, in
# this specific case
exec(function() {
  'foo' %>% assign(x = 'bar', pos = caller_env(6))
  print(exists('bar', inherits = FALSE))
  print(bar)
})
#> [1] TRUE
#> [1] "foo"

# Fails for unknown reasons - maybe there's a `caller_env()` value that would
# work, but I haven't found it
exec(function() {
  list <- list(bar = 'foo')
  list2env(list, envir = caller_env())
  exists('bar', inherits = FALSE)
})
#> [1] FALSE

reprex 包(v0.3.0)于 2020 年 10 月 27 日创建

4

1 回答 1

4

最可靠最简单的方法是将函数的环境存储在一个名称中并引用该名称。

f = function () {
    env = environment()
    'foo' %>% assign('bar', envir = env)
    foo
}

如果你不使用管道,list2env直接工作:

g = function () {
    list = list(foo = 'bar')
    list2env(list, envir = environment())
    foo
}

但在这两种情况下,我通常建议坚持使用列表并避免将变量分配到调用环境中;以下等价于g

g2 = function () {
    list = list(foo = 'bar')
    list$foo
}
于 2020-10-27T13:50:26.823 回答