【问题标题】:Avoiding Global Variables避免全局变量
【发布时间】:2012-12-19 10:14:24
【问题描述】:

我想制作一个基本的分析工具,它可以收集时间戳并生成带有注释的运行时间。唯一的问题是我无法弄清楚如何在不使用全局变量的情况下做到这一点。实现我想要实现的功能的“正确”方法是什么?如果 R 已经内置了这个功能,那就太棒了,但我在这里真正想弄清楚的是如何避免使用全局变量并编写更健壮的代码。

timeStamps = c()
runTimes = list()

appendRunTimes <- function(note) {
  if(length(timeStamps) < 1) {
    timeStamps <<- Sys.time()
  }
  else {
    timeStamps <<- c(timeStamps, Sys.time())
    diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1]
    runTimes <<- c(runTimes,  format(diff))
    names(runTimes)[length(runTimes)] <<-  note
  }

}


appendRunTimes('start')
Sys.sleep(4)
appendRunTimes('test')

【问题讨论】:

  • 我会查看system.time 的代码以获取想法.. 或使用它!您还可以查看一些基准测试包的代码(例如microbenchmark)。
  • 除其他建议外,请参阅“R 简介”(cran.r-project.org/doc/manuals/R-intro.pdf)第 10.7 节,第 50 页(2.15.2 修订版)。

标签: r global-variables


【解决方案1】:

这是使用闭包重写的示例:

RTmonitor <- local({
  timeStamps = c()
  runTimes = list()

  list(
    appendRunTimes=function(note) {
      if(length(timeStamps) < 1) {
        timeStamps <<- Sys.time()
      }
      else {
        timeStamps <<- c(timeStamps, Sys.time())
        diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1]
        runTimes <<- c(runTimes,  format(diff))
        names(runTimes)[length(runTimes)] <<-  note
      }
    },
    viewRunTimes=function() {
      return(list(timeStamps=timeStamps,runTimes=runTimes))
    })
})


> RTmonitor$appendRunTimes("start")
> RTmonitor$appendRunTimes("test")
> RTmonitor$viewRunTimes()
$timeStamps
[1] "2013-01-04 18:39:12 EST" "2013-01-04 18:39:21 EST"

$runTimes
$runTimes$test
[1] "8.855587 secs"

注意这些值存储在闭包内,而不是全局环境中:

> timeStamps
Error: object 'timeStamps' not found
> runTimes
Error: object 'runTimes' not found
> RTmonitor$timeStamps
NULL
> RTmonitor$runTimes
NULL

更多关于闭包和避免全局变量的阅读:

【讨论】:

  • 您距离 R.oo 仅一步之遥,或者可能在这里使用 ReferenceClasses,不是吗?
  • @Spacedman 想要发布 R.oo 或 RefClass 解决方案? :-) 我很想看看其他人的想法。
【解决方案2】:

现在使用 ReferenceClasses 来实现这一点:

RTmonitor = setRefClass("RTmonitor",
  fields=list(
    timeStamps="POSIXct",
    runTimes = "list"
    ),
  methods=list(
    appendRunTimes=function(note){
      if(length(timeStamps)==0){
        timeStamps <<- Sys.time()
      }else{
        timeStamps <<- c(timeStamps, Sys.time())
        diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1]
        runTimes <<- c(runTimes,  format(diff))
        names(runTimes)[length(runTimes)] <<-  note
      }
    }
    )
  )

现在您已经定义了一个类,实例化一个对象并使用它:

> r = RTmonitor$new()
> r$appendRunTimes("start")
> r$appendRunTimes("test")
> r
Reference class object of class "RTmonitor"
Field "timeStamps":
[1] "2013-01-05 14:52:25 GMT" "2013-01-05 14:52:31 GMT"
Field "runTimes":
$test
[1] "5.175815 secs"

与闭包方法非常相似,但更正式。例如,我必须将timeStamps 字段定义为POSIXct。您还可以通过这种方式创建多个 RTmonitor 对象,它们独立工作——您必须编写一个封装了闭包的闭包构造函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-25
    • 1970-01-01
    • 2016-03-19
    • 2012-02-02
    • 2015-12-26
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    相关资源
    最近更新 更多