首页 > 解决方案 > 捕获用于 S3 调度的参数表达式

问题描述

我遇到了 rlang 和 base 之间出乎意料的行为分歧。正如这句话所证明的那样,显然存在差异。这是从 0.4.1 开始的,但类似的语言仍在 0.4.2 中,现在指代enquo

就基本函数而言,enexpr(arg) 对应于 base::substitute(arg)(尽管该函数还具有复杂的替换语义)

  1. 任何人都可以使用具有的 rlang 函数来匹配行为substitute()吗?
  2. 有没有很好的解释为什么enexpr()不起作用?我猜是因为它与 S3 方法调度有关。
  3. 我特别感兴趣如何使用 rlang 来做到这一点,我已经可以使用 base 来实现我想要的行为。

我的例子是无稽之谈,但它强调的是我无法捕获df作为第一个参数传入通用 S3 函数的表达式(在本例中为单个符号,)。

library(rlang)
f <- function(obj) {
  enexpr(obj)
}
print(f(print("hello")))
#> print("hello")
# behavior matches expectations

df <- data.frame(a = 1:5, b = letters[1:5])
class(df) <- c("custom", class(df))
`[.custom` <- function(x, i) {
call2(expr(`[`), enexpr(x), i)
}
df[4]
#> list(a = 1:5, b = 1:5)[4]
sloop::s3_dispatch(df[4])
#> => [.custom
#>  * [.data.frame
#>    [.default
#>  * [ (internal)
# It's dispatching as expected, but I don't get
# `df[4]` back as a call. 

df <- data.frame(a = 1:5, b = letters[1:5])
class(df) <- c("custom", class(df))
`[.custom` <- function(x, i) {
  call2(expr(`[`),substitute(x), i)
}
df[4]
#> df[4]
# substitute works

packageVersion("rlang")
#> [1] '0.4.2'
# Created on 2019-12-05 by the reprex package (v0.3.0)

标签: rrlangtidyeval

解决方案


这是一个记录在案的问题rlang并且可能会在未来的版本中添加支持。

当前的解决方法是在调度时引入另一个级别的引用:

`[` <- function(x, i) {
  ex <- eval_tidy( enquo(x) )
  UseMethod('[', ex)
}

`[.custom` <- function(x, i)
  call2(expr(`[`), enexpr(x), i)

df[4]
# df[4]

推荐阅读