delayedAssign在S4对象槽上

时间:2014-04-04 18:42:58

标签: r s4

我想使用延迟赋值为S4对象的插槽分配新值。 这个赋值基本上是一个数据库查询,我只希望在实际使用该值时执行数据库查询。

但是为了测试,这也可以:

testFunction <- function(id = 1){
  print("running query")
  return(id)
}

delayedAssign("test", testFunction(id = 2))

这很有效。 &#34;运行查询&#34;仅在调用测试时打印,而不是在分配时打印。与之相反:

test2 <- testFunction(id = 2)

现在我希望能够做同样的事情,但后来就是一个插槽。

delayedAssign("someObject@slotName", testFunction(id = 2))

遗憾的是,这会创建一个对象名称“someObject @ slotName&#39;在当前的环境中。 关于如何解决这个问题的任何想法?

1 个答案:

答案 0 :(得分:3)

这代表了一些黑客攻击,具有令人不快的实现细节。这是一个S4类,环境为插槽

.B <- setClass("B", representation(b="environment"))

我注意初始化,所以每个实例都有自己的环境(而不是所有实例共享相同的环境,如果有单例,这将是默认和适当的)

setMethod(initialize, "B",
    function(.Object, ..., b=new.env(parent=emptyenv()))
{
    b[["value"]] <- NA
    callNextMethod(.Object, ..., b=b)
})

让我们定义泛型来设置和检索延迟分配值

setGeneric("delay<-", function(x, ..., value) standardGeneric("delay<-"))
setGeneric("delay", function(x, ...) standardGeneric("delay"))

然后实现方法,在我们的环境中为元素“值”指定值

setReplaceMethod("delay", "B", function(x, ..., value) {
    force(value)                        # don't want to be _too_ lazy
    delayedAssign("value", testFunction(value), assign.env=x@b)
    x
})

并检索它

setMethod("delay", "B", function(x, ...) x@b[["value"]])

这是我们劳动的产物......

>     b <- .B()
>     delay(b)
[1] NA
>     delay(b) <- 1  # no type safety; could use, e.g., delay<-,numeric-method
>     delay(b)
[1] "running query"
[1] 1

带有一些奇怪的引用语义(因为b1和b共享相同的环境)会让我们的用户感到惊讶(甚至可能是我们的用户期望引用语义)

>     b1 <- b         # reference semantics, delayed
>     delay(b1) <- 2
>     delay(b)
[1] "running query"
[1] 2