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

牧云@^-^@ 提交于 2020-01-09 11:24:17

问题


I do understand that generally global variables are evil and I should avoid them, but if my package does need to have a global variable, which of these two approaches are better? And are there any other recommended approaches?

  1. Using an environment visible to the package

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

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

I know there are some other threads that ask about how to achieve global variables, but I haven't seen a discussion on which one is recommended


回答1:


Some packages use hidden variables (variables that begin with a .), like .Random.seed and .Last.value do in base R. In your package you could do

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

But in your package you don't need to assign e. You can use a .onLoad() hook to assign the variable upon loading the package.

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

See this question and its answers for some good explanation on package variables.




回答2:


When most people say you should avoid 'global' variables, they mean you should not assign to the global environment (.GlobalEnv,GlobalEnv, or as.environment(1)) or that you should not pass information between internal functions by any method other than passing such data as the arguments of a function call.

Caching is another matter entirely. I often caching results that I don't want to re-calculate (memoization) or re-query. A pattern I use a lot in packages is the following:

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)
    }

})

The call to local creates a new environment where I can store results using the scoping assignment operator <<- without having to worry about the fact that the package was already sealed, and the last expression (the function definition) is returned as the value of the call to local() and is bound to the name myFunction.



来源:https://stackoverflow.com/questions/28246952/global-variable-in-a-package-which-approach-is-more-recommended

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!