如何在嵌套函数中评估glue表达式?
嗨,我来帮你搞定这个问题~
问题原因&解决方案
先说说你遇到的问题根源
你写的add_prefix("foo")确实能生成正确的字符串,但当你直接把它传给mod_mtcars或mod_mtcars2时,R并没有先求值这个函数调用,而是把整个函数表达式传递了过去,这就导致{{ name }}和ensym()都没法正确识别它:
- 对于
mod_mtcars里的{{ name }},它需要的是裸变量名或者已经求值好的字符串,而不是一个未求值的函数调用,所以报错说LHS不是字符串或符号; - 对于
mod_mtcars2里的ensym(name),它的作用是把裸名称表达式(比如直接写foo)转换成符号,但它没法处理已经求值的字符串或者函数调用结果,所以报错说“Only strings can be converted to symbols”。
可行的解决方案
方案1:提前强制求值后传递
最简单的办法就是让add_prefix("foo")在传递给外部函数前先求值成字符串,你可以用括号包裹表达式,或者先把结果存成变量:
# 用括号强制求值 mod_mtcars(mtcars, (add_prefix("foo"))) # 或者先存变量再传递 new_col_name <- add_prefix("foo") mod_mtcars(mtcars, new_col_name)
这样{{ name }}拿到的就是现成的字符串,就能正常用它作为列名了。
方案2:修改外部函数,兼容字符串输入
如果你想让外部函数直接接受add_prefix的返回值,可以修改函数逻辑,先把输入转换成字符串,再转成符号:
mod_mtcars3 <- function(df, name) { # 先把输入转成字符串,再转换成符号 col_name <- rlang::sym(as.character(name)) df %>% mutate(!!col_name := mpg ^ 2) } # 直接调用就可以生效 mod_mtcars3(mtcars, add_prefix("foo"))
这个版本的函数会先处理输入,不管你传的是glue生成的对象还是字符串,都会先转成字符串再转成符号,完美适配你的需求。
关于“是否应该提前求值”
当然可以提前求值,而且这种做法很合理——当你明确知道需要的是最终的字符串结果时,提前求值能让代码逻辑更清晰,也避免了函数内部处理表达式带来的复杂度。如果你的场景里列名生成逻辑比较固定,提前求值是很直观的选择。
内容的提问来源于stack exchange,提问作者dufei
相关产品推荐
相关产品推荐

