fun1()
、fun2()
和fun3()
看起来都按预期工作:
fun1 <- function(fun, x) {
fun(x)
}
fun1(mean, 1:10)
fun1(as.character, 1:10)
fun1(notafun, 1:10)
fun2 <- function(fun, x) {
fun <- match.fun(fun)
fun(x)
}
fun2(mean, 1:10)
fun2(as.character, 1:10)
fun2(notafun, 1:10)
fun3 <- function(fun, x) {
fun <- deparse(substitute(fun))
do.call(fun, list(x))
}
fun3(mean, 1:10)
fun3(as.character, 1:10)
fun3(notafun, 1:10)
到目前为止,我只注意到如果fun
被指定为字符串(例如"mean"
),match.fun()
也可以工作。
我的用例是一个包中供本地使用的非导出函数(如果我不能将fun()
指定为字符串,这不是一个限制)。使用match.fun()
而不是“直接”提供函数(如fun1()
)有什么好处吗?
2条答案
按热度按时间qni6mghb1#
首先是文档!以下是
?match.fun
的相关部分:当在以函数为参数的函数内部调用时,提取所需的函数对象,同时避免与其他类型的对象进行不必要的匹配。
如果
FUN
是一个函数,则返回它;如果它是一个符号(例如,用反引号括起来)或长度为1的字符向量,则在调用者的父环境中使用get
查找它。因此,
match.fun
具有两个主要优点:1.它为用户提供了传递字符串和符号而不是函数的选项。
1.它提供了 * 类型安全 *,因为返回值总是一个函数。这不仅使你的源代码更健壮,而且更透明:不需要阅读
fun2
的文档就可以知道它的参数fun
必须指定一个函数。而且它几乎不以任何性能成本提供以下优势:
由于这些原因,在尝试计算函数调用之前,最好总是使用
match.fun
进行验证(就像在fun2
中一样),而不是等待并希望调用能够得到评估(就像在fun1
和fun3
中一样)。即使函数没有导出,即使从未传递字符串或符号,因为透明性(见2)使你的源代码更容易阅读和维护。fun3
的独特之处在于它允许用户传递未计算的表达式,但这种方法存在问题,原因有很多:1.在其他函数内部无法按预期工作;请看@Hong Ooi的评论/回答。
1.不能传递使用双冒号或三冒号运算符访问的函数,也不能传递匿名函数,更一般地说,不能传递任何间接计算为函数的表达式:
1.即使它 * 确实 * 如你所期望的那样工作,它也大多是烟雾和镜子:如果
deparse(substitute(fun))
的结果是一个字符串,命名了一个可以从调用环境访问的函数,那么首先就不需要deparse(substitute(fun))
,因为fun
无论如何都会计算出那个函数,它做的额外工作是没有意义的:总之,当你希望函数作为参数时,使用
match.fun
是一个很好的习惯。如果你想接受函数而不接受字符串或符号,你可以避免使用match.fun
,但是在这种情况下,进行测试仍然是一个很好的习惯:ogq8wdun2#
一个关键区别是,如果在封闭函数中调用
fun3
,则fun3
将 * 失败 *,例如:一般来说,除非绝对必要,否则尽量避免非标准的求值技巧。