tidyverse系列的R包虽然解放了大家的双手,但同时也束缚了我们重新编写函数的能力。在这一套语法中,要实现作为函数参数的字符串和变量之间的相互转换困难重重,但只要掌握了其中原理后,也就能够游刃有余地处理了。
首先要理解基础R中几个重要又易忽略的函数。
eval
Evaluate an (Unevaluated) Expression:
Evaluate an R expression in a specified environment.
简言之就是:对表达式对象的求值。
可以把字符串转化成表达式来执行, 通常eval和parse结合使用,参数 text 等于要转化的字符串。
表达式对象不能如下表示:
eval("5+5")
[1] "5+5" #得到的是一个字符串
需要结合parse函数结合text参数来将字符串转化成一个表达式,再进行求值:
> eval(parse(text="5+5"))
[1] 10
> class("5+5")
[1] "character"
> class(parse(text="5+5"))
[1] "expression"
不仅仅求值,eval能调用很多行为,如函数。
> class(eval(parse(text="5+5")))
[1] "numeric"
> class(eval(parse(text="gray"))) #?gray是一个函数
[1] "function"
> class(eval(parse(text="blue")))
Error in eval(expr, envir, enclos) : object 'blue' not found
当然,现在也有一些方法能一步到位。如lazyeval包的lazy_eval函数:
> lazyeval::lazy_eval("5+5")
[1] 10
或用rlang
:
library(rlang)
eval(parse_expr("5+5"))
[1] 10
但我们要清晰地认识到,字符串和表达式两者之间其实是没有任何关系的,这里只是通过parse(text=)连接起来,而parse(text=)的这种方法并不安全,容易出错,应该慎用。我们更多的应该用substitute()
和quote()
函数,接下来我们介绍这两个函数。
Ref: https://stackoverflow.com/questions/1743698/evaluate-expression-given-as-a-string