如何在 R 包中包含闭包?
How to include a closure in an R-package?
我想包含一个闭包,其中包含我们正在编写的 R 包的功能。该函数(及其兄弟函数)将在其环境中包含数据,将输入与数据进行比较,然后 return 结果。为了说明这一点,请考虑一个带有内置电话簿的函数:您查询一个号码,函数 return 是一个名字。
这个函数将被我们的 R 包中的其他几个函数作为助手调用,所以一旦包被加载它就必须存在。我们希望该函数在包环境中可用,就像任何其他函数一样。
我应该通过它在 .onLoad() 中的工厂函数创建它并将它分配给包环境吗?我可以将它作为 .RDS 发送吗?或者 RData,或者这是否违反了 "binary executable code" 上的 CRAN 政策?还是有不同的规范方式?代码和数据(或 RDS/RData)在包目录结构中的什么位置?
(我看到已经讨论了如何 记录 闭包的问题 here)。
为了任何遇到这个问题的人的利益。我最终制定的解决方案涉及几个步骤,但据我所知是 "clean"。
- 将工厂函数放在文件中
R/aaa.R
以确保它在关闭之前加载。
- 将闭包使用的数据放入标准
inst/extdata/
文件夹。
- 将包含闭包名称和正确文档字符串的文件放入
R/
:将闭包定义为普通函数,只是 return 什么都没有。这是必要的,这样函数才能正确导出并在包命名空间中为人所知。立即调用工厂函数创建闭包并覆盖原来的定义。注意:仅仅将数据作为参数传入工厂函数是不够的,实际上需要在定义闭包之前访问它。为什么?那是因为延迟加载实际上不会将数据加载到您需要的环境中,除非您访问它。
就是这样。摘要:为您的闭包创建一个存根,然后用工厂函数的 return 值覆盖它。
如果工厂函数稍后被包用户调用
但我们仍然希望返回的闭包位于包内(例如,如果我们不希望它被除工厂以外的任何东西更改、可以从包内可靠地访问、记录等):
# exported function (visible to user)
# everything this function does is 'outsourced'
# to a non-exported function that we can overwrite with the factory:
visible_function(...){
hidden_function(...)
}
# not exported function (invisible to the user)
# called by the visible function
# fails unless factory is called first
hidden_function(x){
stop("call factory_fun() before you can use visible_function()")
}
# exported function, visible to the user.
# changes the hidden function called by the visible function
factory_function(x){
produced_function<-function(){
print(paste(x, "is an object forever stored in my namespace!"))
}
assignInNamespace("hidden_function",
produced_function,
ns="myPackageName")
}
请注意,R CMD 检查会在 assignInNamespace
上抛出一个注释,因此 CRAN 不会轻易接受此解决方案
我想包含一个闭包,其中包含我们正在编写的 R 包的功能。该函数(及其兄弟函数)将在其环境中包含数据,将输入与数据进行比较,然后 return 结果。为了说明这一点,请考虑一个带有内置电话簿的函数:您查询一个号码,函数 return 是一个名字。
这个函数将被我们的 R 包中的其他几个函数作为助手调用,所以一旦包被加载它就必须存在。我们希望该函数在包环境中可用,就像任何其他函数一样。
我应该通过它在 .onLoad() 中的工厂函数创建它并将它分配给包环境吗?我可以将它作为 .RDS 发送吗?或者 RData,或者这是否违反了 "binary executable code" 上的 CRAN 政策?还是有不同的规范方式?代码和数据(或 RDS/RData)在包目录结构中的什么位置?
(我看到已经讨论了如何 记录 闭包的问题 here)。
为了任何遇到这个问题的人的利益。我最终制定的解决方案涉及几个步骤,但据我所知是 "clean"。
- 将工厂函数放在文件中
R/aaa.R
以确保它在关闭之前加载。 - 将闭包使用的数据放入标准
inst/extdata/
文件夹。 - 将包含闭包名称和正确文档字符串的文件放入
R/
:将闭包定义为普通函数,只是 return 什么都没有。这是必要的,这样函数才能正确导出并在包命名空间中为人所知。立即调用工厂函数创建闭包并覆盖原来的定义。注意:仅仅将数据作为参数传入工厂函数是不够的,实际上需要在定义闭包之前访问它。为什么?那是因为延迟加载实际上不会将数据加载到您需要的环境中,除非您访问它。
就是这样。摘要:为您的闭包创建一个存根,然后用工厂函数的 return 值覆盖它。
如果工厂函数稍后被包用户调用
但我们仍然希望返回的闭包位于包内(例如,如果我们不希望它被除工厂以外的任何东西更改、可以从包内可靠地访问、记录等):
# exported function (visible to user)
# everything this function does is 'outsourced'
# to a non-exported function that we can overwrite with the factory:
visible_function(...){
hidden_function(...)
}
# not exported function (invisible to the user)
# called by the visible function
# fails unless factory is called first
hidden_function(x){
stop("call factory_fun() before you can use visible_function()")
}
# exported function, visible to the user.
# changes the hidden function called by the visible function
factory_function(x){
produced_function<-function(){
print(paste(x, "is an object forever stored in my namespace!"))
}
assignInNamespace("hidden_function",
produced_function,
ns="myPackageName")
}
请注意,R CMD 检查会在 assignInNamespace
上抛出一个注释,因此 CRAN 不会轻易接受此解决方案