我正在编写一个将调用作为输入的函数。然而我注意到 R 有两种不同的方式来创建调用,要么通过
call()
要么通过 quote()
。根据调用的函数,我的代码的行为有所不同,因此我想将两种类型的对象转换为单一对象,以避免扩展代码。
考虑以下两个对象:
call_obj <- "rnorm(5)" |> call()
quote_obj <- rnorm(5) |> quote()
请注意,它们在控制台中打印不同的输出:
> call_obj
`mean()`()
> quote_obj
mean()
但是,它们具有相同的 class、type 和 mode:
> class(call_obj)
[1] "call"
> class(quote_obj)
[1] "call"
> mode(call_obj)
[1] "call"
> mode(quote_obj)
[1] "call"
> typeof(call_obj)
[1] "language"
> typeof(quote_obj)
[1] "language"
> str(call_obj)
language `mean()`()
> str(quote_obj)
language mean()
我已经能够通过两种方法区分这两个物体。
最简单的就是通过
length()
。由于 call_obj
似乎总是返回 1 的长度,而 quote_obj
返回的长度等于调用中显式参数的数量 + 1。但是,如果该函数不能接受显式参数并运行,则这种方法会失败仅使用默认值,例如 mean()
。有没有更强大、简洁的替代方案?尝试了使用 grepl
和反引号的替代方案,但即使它们在 str()
打印输出中可见,它们似乎也没有检测到它们。
复杂的是利用
call_obj
可以通过转换为
quote_obj
这一事实
> all.equal(call_obj[[1]] |> as.character() |> str2lang(), quote_obj)
[1] TRUE
而应用于已经是引用的对象的相同函数将返回
FALSE
:
> all.equal(quote_obj[[1]] |> as.character() |> str2lang(), quote_obj)
[1] "Modes of target, current: name, call"
[2] "target is a subset of current"
额外问题:将
quote_obj
转换为等于 call_obj
的简洁方法是什么?
如果这里有一些非常不
R
的方法,并且还有更惯用的方法,请评论!
您的示例
call_obj <- "rnorm(5)" |> call()
生成对名为 "rnorm(5)"
且不带参数的函数的调用,而不是对带有参数 "rnorm"
的 5
的调用。 如果这就是您真正想要的,那么将 as.character(call_obj[[1]]))
与 as.character(quote_obj[[1]])
进行比较就会显示出差异。
如果您确实希望两者都调用
rnorm(5)
,那么您需要使用
call_obj <- "rnorm" |> call(5)
结果将与您在
quote_obj
中得到的结果相同。