rlang 包中的 sym() 和 parse_expr() 有什么区别?

What is the difference between sym() and parse_expr() in the rlang package?

使用rlang包,想知道sym()parse_expr()有什么区别。例如考虑以下表达式:

ex1 = sym('a')
ex2 = parse_expr('a')

他们俩return

a

identical(ex1, ex2)
[1] TRUE

假设现在我需要一个quosure:

ex3 = quo(!!sym('a'))
ex4 = quo(!!parse_expr('a'))

在这两种情况下,结果都是:

<quosure>
expr: ^a
env:  global

identical(ex3, ex4)
[1] TRUE

但是,由于某些原因,以下两个并不相同。

ex5 = quo(!!sym('a - b'))
ex6 = quo(!!parse_expr('a - b'))

显然它们是相同的 return:

<quosure>
expr: ^a - b
env:  global

还有,

identical(ex5, ex6)
[1] FALSE

所以,我的问题是,sym()parse_expr() 之间有什么区别? 一个人能做什么而另一个人不能?为什么 ex5 明显类似于 ex6,但 identical(ex5, ex6) return 是假的?

参考我对此的回答

符号是指代 R 对象的一种方式,基本上是对象的“名称”。所以 sym 类似于基础 R 中的 as.name。另一方面,parse_expr 将一些文本转换为 R 表达式。这类似于基础 R 中的 parse

表达式可以是任何 R 代码,而不仅仅是引用 R 对象的代码。所以你可以解析引用R对象的代码,但是如果代码引用的对象不存在,你不能将一些随机代码变成sym

通常,当您的字符串引用一个对象时,您将使用 sym(尽管 parse_expr 也可以),并在您尝试解析任何其他对象时使用 parse_expr用于进一步评估的 R 代码。

对于您的第一个示例,a 可以是引用对象的名称和表达式,因此将其转换为 symparse_expr 实际上意味着相同事物。事实上,R 会在可能的情况下将表达式隐式转换为 sym,如第一个示例所示。

然而,对于您的最后一个示例,a - b 实际上是一个表达式(除非您有一个奇怪地命名为 a - b 的 R 对象)。通过打印以下内容,您将看到使用 symparse_expr 的 R 代码 是一个表达式,而不是 R 对象 会产生两个不同的结果:

> quo(!!sym('a - b'))
<quosure: global>
~`a - b`

> quo(!!parse_expr('a-b'))
<quosure: global>
~a - b

在这里,syma - b 变成一个对象的 name/symbol,因此在 a - b 周围打勾, while parse_expr 将其转换为预期的表达式。

为了补充前面的答案,请注意 ex5ex6 实际上并不相同。

a <- 5
b <- 3
eval_tidy(ex6)
# [1] 2
eval_tidy(ex5)
# Error in eval_tidy(ex5) : object 'a - b' not found
`a - b` <- pi
eval_tidy(ex5)
# [1] 3.141593