使用 rlang::eval_tidy 时理解赋值

Understanding assignment when using rlang::eval_tidy

我想了解为什么在使用 rlang::eval_tidy 评估 <- 赋值操作时会发生以下情况。

让我们使用 rlang::expr 创建一个表达式来为变量 x 赋值 1。

x_expr <- rlang::expr(x <- 1)

我们还创建了一个要在其中计算表达式的环境。

new_env <- new.env(parent = parent.env(environment()))

我的意图是将1赋值给new_env里面的x

现在,我们使用 base::eval 来计算这个表达式:

eval(x_expr, envir = new_env)
get('x', envir = new_env)

这个returns1。如果我们简单地在全局环境中评估 x,我们会得到一个错误(表明 xnew_env 中而不是从全局环境中获取)。
我们可以从 new_env 中删除 x,然后使用 rlang::eval_bare:

重新分配它
rm('x', envir = new_env)
rlang::eval_bare(x_expr, env = new_env)
get('x', envir = new_env)

同样,这给出 1

现在,我们再次从 new_env 中删除 x,并尝试使用 rlang::eval_tidy 重新分配它。但是,在这种情况下,当我们在 new_env:

中查找 x 时会出错
rm('x', envir = new_env)
rlang::eval_tidy(x_expr, env = new_env)
get('x', envir = new_env)

为什么会这样?我假设 x 已分配给 1,但在哪?

sessionInfo():

R version 4.1.0 (2021-05-18)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19042)

Matrix products: default

locale:
[1] LC_COLLATE=English_South Africa.1252  LC_CTYPE=English_South Africa.1252   
[3] LC_MONETARY=English_South Africa.1252 LC_NUMERIC=C                         
[5] LC_TIME=English_South Africa.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] compiler_4.1.0 tools_4.1.0    yaml_2.2.1     rlang_0.4.11  

来自 eval_tidy() 上的 documentation

eval_tidy() always evaluates in a data mask, even when data is NULL. Because of this, it has different stack semantics than base::eval():

  • Lexical side effects, such as assignment with <-, occur in the mask rather than env.

我们可以通过在 tidy_eval()

期间添加数据掩码来确认这一点
library(rlang)

x_expr <- rlang::expr(x <- 1)
new_env <- new.env(parent = parent.env(environment()))
data_mask <- rlang::new_data_mask(new.env(parent = parent.env(environment())))

rlang::eval_tidy(x_expr, data_mask, env = new_env)

get('x', envir = data_mask) ## Returns 1