强制评估函数参数以便 "trick" 替代()?

Force-evaluate function argument in order to "trick" substitute()?

假设我有一个来自 R 包的函数,为了方便和更好的代码可读性,我想将其包装在一个闭包中。为简单起见,我们假设函数如下所示:

fun <- function(text) {
    as.character(substitute(text))
}

当我从控制台调用该函数时,例如

fun(text = "bar")

返回值是 "bar",在我的例子中这是期望的行为。函数按原样编写的原因是万一我调用

fun(text = bar)

输出也是"bar"。仅供参考。这个功能我明明不是自己写的,只是想用一下

问题: 当我从一个函数中调用 fun 时,例如

fun2 <- function(foo) {
    fun(text = foo)
}
fun2(foo = "bar")

无论我在调用 fun2 时分配给 foo 什么,输出总是 "foo" 而不是“bar”。 Ofc 我知道这就是 substitute() 的工作方式,但这使得无法(或者至少非常讨厌?)以编程方式使用函数 fun.

我的问题:有没有一种方法可以在不重写的情况下实现所需的行为fun

提前致谢:)

您可以在 fun2 中构造调用并对其求值:

fun2 <- function(foo) {
  eval(call("fun", foo))
}

fun2(foo = "bar")
#> [1] "bar"

这里的问题是,如果您通过 bar 未加引号:

,它现在不再有效
fun2(foo = bar)
#> Error in eval(call("fun", foo)) : object 'bar' not found

所以你需要这样的东西:

fun2 <- function(foo) {
  if(exists(as.character(substitute(foo)), parent.frame())) {
    eval(call("fun", foo))
  } else {
    eval(call("fun", as.character(substitute(foo))))
  }
}

现在两种方式都有效:

fun2(foo = "bar")
#> [1] "bar"

fun2(foo = bar)
#> [1] "bar"

这里的问题是,如果bar确实存在,那么它会被解释为bar的值,所以我们有:

fun2(foo = "bar")
#> [1] "bar"

fun2(foo = bar)
#> [1] "bar"

bar <- 1

fun2(foo = bar)
#> [1] "1"

这可能不是您想要的。

但是,如果您要这样做,调用 fun 可能就不再有意义了。也许最简单的事情是

fun2 <- function(foo) {
  as.character(match.call()$foo)
}

fun2("bar")
#> [1] "bar"

fun2(bar)
#> [1] "bar"

bar <- 1

fun2(bar)
#> [1] "bar"