You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用rlang::inject()结合数据掩码时如何保留调用上下文以简化准引用表达式求值?

rlang::inject()结合数据掩码时如何保留调用上下文以简化准引用表达式求值?

我最近在写R代码时遇到了一个关于整洁求值的问题:我想实现一个简单函数,输入是data.frame,要在这个数据的上下文里求值一个包含准引用列的表达式。

目前我用rlang包里的expr()和eval_tidy()已经能实现需求了,代码是这样的:

library(rlang)

fn_eval <- function(x, col) {
  eval_tidy(data = x, expr(
    
    # 这里是涉及目标列的表达式
    max({{ col }})
    
  ))
}

这个写法能正确对传入的列参数解引用,然后求值表达式。测试一下:

df <- data.frame(A = 1:5)

fn_eval(df, A)
#> [1] 5

结果没问题,但我总觉得eval()的嵌套写法有点冗余,想简化一下。于是我试着直接用inject(),把as_data_mask(x)作为环境参数传进去,代码改成了这样:

fn_inj <- function(x, col) {
  inject(env = as_data_mask(x),
    
    # 同样是涉及目标列的表达式
    max({{ col }})
    
  )
}

但运行的时候出问题了——max()函数直接找不到,报了这个错:

fn_inj(df, A)
#> Error in max(~A) : could not find function "max"

更麻烦的是,就算我写成base::max()也没用,因为::运算符也不在这个数据掩码的作用域里——说白了,数据掩码外面的所有东西都访问不到。显然inject()这里的行为和eval_tidy()创建的数据掩码完全不一样。

现在我有两个具体的问题想请教:

我的疑问

  1. 怎么给inject()创建一个能继承调用上下文的数据掩码,让max()这类常用函数保持在作用域里?
    我查了as_data_mask的文档,里面说不能直接修改掩码的父环境:

    注意:顶层环境的父环境是完全不确定的,你不能指望它一直保持不变。在求值过程中,eval_tidy()会把这个父环境替换成以下环境之一...

    但我真的不想手动把需要的函数一个个绑定到掩码里,因为这样每次表达式依赖的函数变化时,我都得手动更新绑定,太繁琐了。文档里还提到过:

    在某些情况下,你的数据掩码需要多个层级。一个很好的理由是当你在掩码中包含函数时。最好把数据对象放在比函数对象低的层级,这样前者就不会覆盖后者的定义(见示例)。

  2. 有没有标准的、推荐的写法,可以在x的上下文中求值准引用表达式,同时让x的列能覆盖调用环境?
    理想情况是这个写法用到的数据掩码完全支持整洁求值的所有特性:比如准引用、.data代词这些都能正常工作。

备注:内容来源于stack exchange,提问作者Greg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 18:28:05