我知道其他有关substitute
、quote
和eval
的答案(例如这个答案)。然而,我仍然对以下情况感到困惑。为了确保我正在尝试做的事情清楚,我会在下面的步骤中错误地使用冗长的方式。
假设我有四个函数(即下面看到的),它们都接受一个expression
,将其传递,并且只有根函数评估它。
f1 <- function(expr) {
x <- "Hello!"
do.call(eval, list(expr = expr))
}
f2 <- function(expr) {
f1(expr)
}
f3 <- function(expr) {
f2(expr)
}
f4 <- function(expr) {
f3(expr)
}
接下来,我对于将一个未加引号的表达式传递给f2
、f3
或者f4
并且不希望立即执行它感兴趣。更具体地说,我想要调用:
f4(print(paste0("f4: ", x)))
f3(print(paste0("f3: ", x)))
f2(print(paste0("f2: ", x)))
请观察以下输出结果:
[1] "f4: Hello!"
[1] "f3: Hello!"
[1] "f2: Hello!"
然而,现在调用例如f4(print(paste0("f4: ", x)))
会导致错误,因为x
未被定义,直到f1
的环境中才被定义:
Error in paste0("x: ", x) : object 'x' not found
我可以在 f4
中使用 substitute
来获取表达式的解析树,例如:
f4 <- function(expr) {
f3(substitute(expr))
}
然后调用该函数。
f4(print(paste0("f4: ", x)))
并获得:
[1] "f4: Hello!"
[1] "f4: Hello!"
双重输出可能是因为
f1
中的参数 expr
没有加引号导致早期计算。添加引号即可解决此问题:eval
。f1 <- function(expr) {
x <- "Hello!"
do.call(eval, list(expr = quote(expr)))
}
f4(print(paste0("f4: ", x)))
# [1] "f4: Hello!"
如果我将同样的逻辑应用于,比如说,
f3
,例如:f3 <- function(expr) {
f2(substitute(expr))
}
调用f3
的效果与预期相符,即:
f3(print(paste0("f3: ", x)))
# [1] "f3: Hello!"
但是现在调用
f4
失败了,输出的结果是 expr
。f4(print(paste0("f4: ", x)))
目前,我并不确定如何实现这一点,甚至不确定是否可能实现。
当然,最简单的方法是将带引号的表达式传递给任何一个这些函数。但是,我想知道如何在没有quote
的情况下实现这一点。
print()
?不添加这个额外的层,示例会更或多或少相同吗?还是你想让函数正确处理print()
语句? - TimTeaFan