【问题标题】:How to include a closure in an R-package?如何在 R 包中包含闭包?
【发布时间】:2025-12-30 17:35:10
【问题描述】:

我想包含一个带有我们正在编写的 R 包的功能的闭包。该函数(及其兄弟)将在其环境中拥有数据,执行输入与数据的比较,并返回结果。举例来说,考虑一个具有内置电话簿的函数:您使用一个号码进行查询,该函数返回一个名称。

这个函数将被我们的 R 包中的其他几个函数作为助手调用,所以一旦包被加载,它就必须存在。我们希望该函数在包环境中可用,就像任何其他函数一样。

我应该通过它在 .onLoad() 中的工厂函数创建它并将其分配给包环境吗?我可以将它作为 .RDS 发送吗?或者 RData,或者这是否违反了 CRAN 关于“二进制可执行代码”的政策?还是有不同的规范方式?代码和数据(或 RDS/RData)会放在包目录结构中的什么位置?

(我看到关于如何记录闭包的问题已经讨论过here)。

【问题讨论】:

  • alistaire - 此关闭预计不会更改。因此使用 onLoad 创建它似乎没有错 - 不是吗?
  • @alistaire - “R 仍然不允许你将它分配给包命名空间”我可能误解了 ns-hooks 文档 - 但我认为这意味着这就是.onLoad().onAttach() 用于:.onLoad() 处理在命名空间被密封之前需要发生的事情,.onAttach() 用于在环境被密封之前需要发生的事情。
  • 这个问题实际上只涵盖了问题标题的一个特殊情况:如何在 R 包中包含一个闭包,当且仅当工厂在加载时被调用。如果用户在加载包后调用工厂,并在包内部生成/修改函数,那么任何人都有解决方案?
  • 我刚刚拒绝了@Ma Ba 对我的自我回应的深思熟虑的编辑。我认为他们的方法很有用,但我真的不能在我的回复中声称对它的信任(而且它与所述的原始问题没有直接关系)。所以:请添加您的建议作为您自己的回复。
  • 感谢@hyginn;同意。我将其添加为答案,因为这是搜索问题时弹出的第一件事,并且在其他任何地方都找不到解决方案

标签: r r-package


【解决方案1】:

为了任何绊倒这个问题的人的利益。我最终制定的解决方案涉及几个步骤,但据我所知是“干净的”。

  1. 将工厂函数放入文件R/aaa.R 以确保它在关闭之前被加载。
  2. 将闭包使用的数据放入标准的inst/extdata/文件夹中。
  3. 将带有闭包名称和正确文档字符串的文件放入R/:将闭包定义为一个不返回任何内容的普通函数。这是必要的,因此该函数被正确导出并在包命名空间中已知。立即调用工厂函数创建闭包并覆盖原始定义。注意:仅仅将数据作为参数带入工厂函数是不够的,实际上需要在定义闭包之前对其进行访问。为什么?这是因为延迟加载实际上不会将数据加载到您需要它的环境中,除非您访问它。

就是这样。摘要:为你的闭包创建一个存根,然后用工厂函数的返回值覆盖它。

【讨论】:

    【解决方案2】:

    如果工厂函数被包用户稍后调用

    但我们仍然希望返回的闭包在包内(例如,如果我们不希望它被工厂以外的任何东西更改,从包内可靠地访问,记录等):

    # 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 不会轻易接受此解决方案

    【讨论】: