local()与R中的其他闭包方法有何不同?

local()与R中的其他闭包方法有何不同?,r,closures,local,static-variables,R,Closures,Local,Static Variables,昨天我从Bill Venables那里学到了local()如何帮助创建静态函数和变量,例如 example <- local({ hidden.x <- "You can't see me!" hidden.fn <- function(){ cat("\"hidden.fn()\"") } function(){ cat("You can see and call example()\n") cat("but you can't see

昨天我从Bill Venables那里学到了local()如何帮助创建静态函数和变量,例如

example <- local({
  hidden.x <- "You can't see me!"
  hidden.fn <- function(){
    cat("\"hidden.fn()\"")
  }
  function(){
    cat("You can see and call example()\n")
    cat("but you can't see hidden.x\n")
    cat("and you can't call ")
    hidden.fn()
    cat("\n")
  }
})
我在一个采用不同方法的地方看到过这种讨论


这两种方法的优缺点是什么?

封装

这种编程风格的优点是隐藏的对象不可能被其他任何东西覆盖,因此您可以更加确信它们包含您的想法。它们不会被错误使用,因为它们不容易被访问。在问题的链接帖子中有一个全局变量,
count
,它可以从任何地方访问和覆盖,因此如果我们调试代码,查看
count
,并查看其更改,我们无法确定代码的哪个部分更改了它。相比之下,在问题的示例代码中,我们可以更大程度地保证不涉及代码的其他部分

请注意,我们实际上可以访问隐藏函数,尽管它不是那么容易:

# run hidden.fn
environment(example)$hidden.fn()
面向对象编程

还请注意,这与面向对象编程非常接近,其中
示例
隐藏.fn
是方法,
隐藏.x
是属性。我们可以这样做,使其明确:

library(proto)
p <- proto(x = "x", 
  fn = function(.) cat(' "fn()"\n '),
  example = function(.) .$fn()
)
p$example() # prints "fn()"
local()

getMPIcluster <- NULL
setMPIcluster <- NULL
local({
    cl <- NULL
    getMPIcluster <<- function() cl
    setMPIcluster <<- function(new) cl <<- new
})

(通常的记忆例子,斐波那契数,并不令人满意——不会溢出R的数值表示的数字范围很小,因此人们可能会使用一个高效预计算值的查找表)。有趣的是,这里的爬虫是一个单身汉;可以很容易地遵循工厂模式,因此每个基本URL都有一个爬虫。

另一个方便的模式是记忆。在地狱中的某个地方有一个例子。你认为爬虫是一个单例的想法很有趣,因为本地的一个替代方法是立即计算一个匿名函数而不带任何参数-工厂模式可能会在基本url上使用闭包。
ch <- p$proto(fn = function(.) cat("Hello from ch\n")) # child
ch$example() # prints: Hello from ch
getMPIcluster <- NULL
setMPIcluster <- NULL
local({
    cl <- NULL
    getMPIcluster <<- function() cl
    setMPIcluster <<- function(new) cl <<- new
})
library(XML)
crawler <- local({
    seen <- new.env(parent=emptyenv())
    .do_crawl <- function(url, base, pattern) {
        if (!exists(url, seen)) {
            message(url)
            xml <- htmlTreeParse(url, useInternal=TRUE)
            hrefs <- unlist(getNodeSet(xml, "//a/@href"))
            urls <-
                sprintf("%s%s", base, grep(pattern, hrefs, value=TRUE))
            seen[[url]] <- length(urls)
            for (url in urls)
                .do_crawl(url, base, pattern)
        }
    }
    .do_report <- function(url) {
        urls <- as.list(seen)
        data.frame(Url=names(urls), Links=unlist(unname(urls)),
                   stringsAsFactors=FALSE)
    }
    list(crawl=function(base, pattern="^/.*html$") {
        .do_crawl(base, base, pattern)
    }, report=.do_report)
})

crawler$crawl(favorite_url)
dim(crawler$report())