首页 > 解决方案 > 如何评估嵌套函数中的胶水表达式?

问题描述

我正在尝试嵌套一个将两个字符串粘合在一起的函数,该函数使用组合字符串来命名数据框的列。但是,问题似乎是胶水表达式没有足够早地评估为字符串。我可以(并且应该)在将表达式作为参数传递给另一个函数之前强制对其进行评估吗?

library(tidyverse)

# define inner function
add_prefix <- function(string) {
  x <- glue::glue("prefix_{string}")
  return(as.character(x))
}

# define outer function
mod_mtcars <- function(df, name) {
  df %>% 
    mutate({{ name }} := mpg ^ 2)
}

mod_mtcars(mtcars, add_prefix("foo"))
#> Error: The LHS of `:=` must be a string or a symbol

# alternative outer function with explicit enquoting
mod_mtcars2 <- function(df, name) {
  name <- ensym(name)
  
  df %>% 
    mutate(!!name := mpg ^ 2)
}

mod_mtcars2(mtcars, add_prefix("foo"))
#> Error: Only strings can be converted to symbols

reprex 包于 2021-10-30 创建(v2.0.1)

标签: rmetaprogrammingtidyeval

解决方案


首先,胶合字符串语法现在比直接在 LHS 中包含更受欢迎。所以更"{{ var }}" := expr喜欢{{ var }} := expr. 在 rlang 的未来版本(明年)中,我们将可以在=. 到那时,:=将几乎被取代。在添加胶水支撑之前,我们允许在 LHS 上:=进行注射。!!

其次,您的问题是您正在使用{{而不是简单的注入。{{用于注入作为参数提供的表达式,而不是表达式的。使用普通的胶水插值"{"来注入值:

mod_mtcars <- function(df, name) {
  df %>% 
    mutate("{name}" := mpg ^ 2)
}

PS:你的!!版本有类似的问题。因为您ensym()在参数上使用了,所以您正在解析作为参数提供的表达式而不是使用值。但是ensym()要求表达式是一个简单的名称,并且您提供了完整的计算,从而导致错误。你可以像这样修复它:

mod_mtcars2 <- function(df, name) {
  df %>%
    mutate(!!name := mpg ^ 2)
}

但是现在首选胶合语法。


推荐阅读