【发布时间】:2018-10-18 08:22:18
【问题描述】:
我正在开发一个 R 包,其中我有一个导出函数,该函数需要调用几个未导出的函数并将每个函数的结果存储在一个列表中。 调用哪些函数是可变的,取决于用户输入。
我的处理方法是 lapply 一个函数名称的(字符)向量与 do.call,但这似乎使未导出的函数对导出的函数不可见。
考虑以下示例包代码:
tmp1 <- function(x) print(paste("Function 1 called with x =", x))
tmp2 <- function(x) print(paste("Function 2 called with x =", x))
tmp3 <- function(x) print(paste("Function 3 called with x =", x))
#' @export
test1 <- function() {
tmp1("test")
tmp2("test")
tmp3("test")
}
#' @export
test2 <- function() {
funs <- c("tmp1", "tmp2", "tmp3")
for (fun in funs) do.call(fun, list(x = "test"))
}
#' @export
test3 <- function() {
funs <- c("tmp1", "tmp2", "tmp3")
lapply(funs, do.call, list(x = "test"))
}
构建和加载包后,运行三个test 函数会产生以下输出:
test1()
#> [1] "Function 1 called with x = test"
#> [1] "Function 2 called with x = test"
#> [1] "Function 3 called with x = test"
test2()
#> [1] "Function 1 called with x = test"
#> [1] "Function 2 called with x = test"
#> [1] "Function 3 called with x = test"
test3()
#> Error in tmp1(x = "test"): could not find function "tmp1"
直接调用函数有效,直接用do.call调用时用do.call调用有效,但用lapply调用时失败。
我可以使用 for 循环解决问题,但我很好奇为什么会发生这种情况。
所以,我的问题是双重的:
- 为什么在
lapply内部调用时,未导出的函数对do.call不可见? - 我可以让
lapply(funs, do.call, list(...))方法起作用吗?
【问题讨论】:
-
我无法重现您的错误。当我用你的代码创建一个包时,它对我来说很好。但是,无论如何,我认为当你编写一个包时,你应该使用
::指定这些函数的位置。 -
使用
funs <- c(tmp1, tmp2, tmp3)代替funs <- c("tmp1", "tmp2", "tmp3")能解决您的问题吗?或者做lapply(mget(funs), do.call, list(x = "test")),这相当于 -
@Moody_Mudskipper 它使
test3运行,但它没有回答我的问题(即为什么lapply方法失败),此外,在我的实际包中,funs将是用户(在某种程度上)指定的字符向量。 -
然后使用
mget应该可以解决它,尽管它没有回答为什么它不起作用。恕我直言,使用函数对象更干净。 -
do.call默认情况下在parent.frame()中评估其字符参数,当使用lapply时,您正在做一些使您的代码失败的环境体操(不幸的是,我不知道多说更多),因此您也可以通过调整envir参数来解决您的问题。来自?do.call:envir an environment within which to evaluate the call. This will be most useful if what is a character string and the arguments are symbols or quoted expressions.