R包函数中使用bang-bang(!!)和walrus(:=)的最佳实践
针对R包中引用rlang操作符!!、:=的解决方案
核心前提:!!(bang-bang)和:=(walrus)属于rlang整洁评估框架的语法糖,不是普通的顶层函数,因此不能直接用rlang::!!的形式调用,你可以通过以下3种方式实现明确的包依赖关联,避免运行结果依赖本地环境提前加载rlang:
- 方案1:导入操作符到包命名空间(最常用)
如果你经常使用这两个操作符,可以通过roxygen2注解明确导入:
在包内任意R脚本的顶部添加注解:
执行#' @importFrom rlang !! := NULLdevtools::document()后会自动在NAMESPACE文件生成对应的导入规则,同时需要在DESCRIPTION的Imports字段添加rlang依赖,即可在包内所有函数中直接使用这两个操作符,和导入其他普通函数的效果完全一致。 - 方案2:用
rlang::inject()包裹调用(零导入、无命名空间污染)
如果不想额外导入操作符到命名空间,可以直接用rlang提供的inject()函数包裹所有用到这两个操作符的代码,此时inject的解析器会自动识别内部的!!和:=,不需要额外导入:
示例写法:
这种方式完全符合# 原写法 dplyr::mutate(df, !!new_col_name := !!old_col * 2) # 替换后写法,无需导入任何rlang操作符 rlang::inject(dplyr::mutate(df, !!new_col_name := !!old_col * 2))package::function()的明确引用规范,不会向你的包命名空间导入任何额外对象,是最贴近你要求的实现方案。 - 方案3:使用操作符的函数别名
!!的函数别名为rlang::UQ(),你可以直接用函数形式调用,不过:=没有对应的独立函数别名,这种方式只适合仅用到!!的场景。
验证方法
你可以通过以下操作确认运行结果不依赖本地预加载的rlang:
- 关闭当前所有R会话,启动新的干净R会话
- 运行
pkgload::load_all(your_package_path, export_all = FALSE, attach_testthat = FALSE),不要手动加载rlang - 调用你用到
!!/:=的函数,确认可以正常运行无报错
另外你也可以直接执行devtools::install()把包安装到本地库,再在干净环境中library(你的包名)调用测试,结果会更准确。
内容的提问来源于stack exchange,提问作者Guillermo
相关产品推荐
相关产品推荐

