计数器的非全局版本使用词法作用域来封装idCounter
和增量函数。
emitID <- local({
idCounter <- -1L
function(){
idCounter <<- idCounter + 1L
formatC(idCounter, width=9, flag=0, format="d")
}
})
然后
> emitID()
[1] "000000000"
> emitID1()
[1] "000000001"
> idCounter <- 123 ## global variable, not locally scoped idCounter
> emitID()
[1] "000000002"
一种有趣的替代方案是使用“工厂”模式创建独立计数器。您的问题暗示您将调用此函数十亿次(嗯,不确定我从哪里得到这个印象...),因此也许通过创建id缓冲区来向量化对formatC的调用是有意义的。
idFactory <- function(buf_n=1000000) {
curr <- 0L
last <- -1L
val <- NULL
function() {
if ((curr %% buf_n) == 0L) {
val <<- formatC(last + seq_len(buf_n), width=9, flag=0, format="d")
last <<- last + buf_n
curr <<- 0L
}
val[curr <<- curr + 1L]
}
}
emitID2 <- idFactory()
然后(emitID1
是上面本地变量版本的实例)。
> library(microbenchmark)
> microbenchmark(emitID1(), emitID2(), times=100000)
Unit: microseconds
expr min lq median uq max neval
emitID1() 66.363 70.614 72.310 73.603 13753.96 1e+05
emitID2() 2.240 2.982 4.138 4.676 49593.03 1e+05
> emitID1()
[1] "000100000"
> emitID2()
[1] "000100000"
(尽管速度并不是一切,但原型解决方案大约比 emitID1
慢3倍)。