包中的全局变量 - 更推荐哪种方法?

Global variable in a package - which approach is more recommended?

我知道全局变量通常是有害的,我应该避免使用它们,但是如果我的包确实需要一个全局变量,这两种方法中哪一种更好?还有其他推荐的方法吗?

  1. 使用包可见的环境

    pkgEnv <- new.env()  
    pkgEnv$sessionId <- "xyz123"
    
  2. 使用options

    options("pkgEnv.sessionId" = "xyz123")
    

我知道还有其他一些帖子在问如何实现全局变量,但是我没有看到推荐使用哪一个的讨论

当大多数人说您应该避免 'global' 变量时,他们的意思是您不应该分配给全局环境(.GlobalEnvGlobalEnvas.environment(1))或除了将此类数据作为函数调用的参数传递之外,您不应通过任何方法在内部函数之间传递信息。

缓存完全是另一回事。我经常缓存不想重新计算(记忆)或重新查询的结果。我在包中经常使用的模式如下:

myFunction <- local({

    cache <- list() # or numeric(0) or whatever

    function(x,y,z){ 

        # calculate the index of the answer 
        # (most of the time this is a trivial calculation, often the identity function)
        indx = answerIndex(x,y,z)

        # check if the answer is stored in the cache
        if(indx %in% names(cacheList))
            # if so, return the answer
            return(cacheList[indx])

        [otherwise, do lots of calculations or data queries]

        # store the answer
        cahceList[indx] <<- answer

        return(answer)
    }

})

local 的调用创建了一个新环境,我可以在其中使用作用域赋值运算符 <<- 存储结果,而不必担心包已经密封,最后一个表达式(函数定义)作为调用 local() 的值返回并绑定到名称 myFunction.

有些包使用隐藏变量(以 . 开头的变量),例如 .Random.seed.Last.value 在 base R 中使用。在你的包中你可以做

e <- new.env()
assign(".sessionId", "xyz123", envir = e)
ls(e)
# character(0)
ls(e, all = TRUE)
# [1] ".sessionId"

但是在你的包中你不需要分配e。您可以使用 .onLoad() 挂钩在加载包时分配变量。

.onLoad <- function(libname, pkgname) {
    assign(".sessionId", "xyz123", envir = parent.env(environment()))
}

请参阅 this question 及其答案,了解有关包变量的一些很好的解释。