在检索 S4 参考类的字段值时避免考虑封闭帧

Posted

技术标签:

【中文标题】在检索 S4 参考类的字段值时避免考虑封闭帧【英文标题】:Avoiding consideration of enclosing frames when retrieving field value of a S4 Reference Class 【发布时间】:2013-03-09 21:13:08 【问题描述】:

我非常喜欢 S4 引用类,因为它们允许混合编程风格(函数式/按值传递与 oop/按引用传递;example),从而显着提高了灵活性。

但是,当您要求 R 通过方法 $field() 检索某个字段值时,我认为我只是遇到了一种关于 R 扫描环境/帧的方式的不良行为(请参阅 help page)。问题是,如果在实际的本地/目标环境(这将是构成 S4 参考类的环境)中找不到所需的字段,R 似乎也会查看封闭环境/框架,即就像运行 get(<objname>, inherits=TRUE) (见help page)。

实际问题

为了让 R 只在本地/目标环境中查看,我在想类似 $field(name="<fieldname>", inherits=FALSE)$field() 没有 ... 参数可以让我将 inherits=FALSE 传递给 @ 987654330@ (我猜它在路上的某个地方被称为)。有解决办法吗?


代码示例

对于那些对更多细节感兴趣的人:这里有一个说明行为的小代码示例

setRefClass("A", fields=list(a="character"))

x <- getRefClass("A")$new(a="a")

A类中有一个字段a,所以在目标环境中找到并返回值:

> x$field("a")
[1] "a"

如果我们尝试访问一个不是引用类的字段但恰好与工作区/搜索路径中的某个其他对象的名称相同的字段(在此案例"lm"):

require("MASS")
> x$field("lm")

function (formula, data, subset, weights, na.action, method = "qr", 
    model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
    contrasts = NULL, offset, ...) 

    ret.x <- x
    ret.y <- y

    [omitted]

    if (!qr) 
        z$qr <- NULL
    z

<bytecode: 0x02e6b654>
<environment: namespace:stats>

在这一点上并不是我所期望的。恕我直言,一个错误或至少一个警告会好得多。或者打开方法$field() 用于可以通过... 传递给其他函数的参数。我猜想在调用$field() 时会调用get(),所以这样的事情可能会阻止上述行为的发生:

x$field("digest", inherits=FALSE)

解决方法:自己的提议

这应该可以解决问题,但也许有一些更优雅的东西不涉及在 $field() 之上指定新方法:

setRefClass("A", fields=list(a="character"),
    methods=list(
        myField=function(name, ...) 
            # VALIDATE NAME //
            if (!name %in% names(getRefClass(class(.self))$fields())) 
                stop(paste0("Invalid field name: '", name, "'"))
            
            # //
            .self$field(name=name)
        
    )
)
x <- getRefClass("A")$new(a="a")

> x$myField("a")
[1] "a"
> x$myField("lm")
Error in x$myField("lm") : Invalid field name: 'lm'

【问题讨论】:

我认为一般的做法是 i) 提出问题,ii) 等待 Martin Morgan 过来回答 ;-) @DirkEddelbuettel:哈哈哈......好一个;-) 顺便说一句,您可以在示例中使用require(MASS)lm(这样它就不需要外部包)。 @csgillespie:很好,谢谢! 【参考方案1】:

默认的field() 方法可以替换成你自己的。所以添加一个inherits 参数来避免封闭框架只是抓住现有的x$field 定义并添加它的问题......

setRefClass( Class="B",
             fields= list( a="character" ),
             methods= list(
               field = function(name, value, inherits=TRUE ) 
                 if( missing(value) ) 
                   get( name, envir=.self, inherits=inherits )
                  else 
                   if( is.na( match( name, names( .refClassDef@fieldClasses ) ) ) ) 
                     stop(gettextf("%s is not a field in this class", sQuote(name)), domain = NA)
                   
                   assign(name, value, envir = .self)
                 
               
             ),
)

或者你可以通过一些重新排列得到一个很好的错误信息

setRefClass( Class="C",
             fields= list( a="character" ),
             methods= list(
               field = function(name, value, inherits=TRUE ) 
                if( is.na( match( name, names( .refClassDef@fieldClasses ) ) ) &&
                      ( !missing(value) || inherits==FALSE) ) 
                  stop(gettextf("%s is not a field in this class", sQuote(name)), domain = NA)
                

                if( missing(value) ) 
                    get( name, envir=.self, inherits=inherits )
                 else 
                  assign(name, value, envir = .self)
                
               
             ),
)

由于您可以定义任何自己的方法来替换默认值,因此几乎可以为您的 refclasses 实现您想要的任何逻辑。如果使用继承获取变量但模式与 c("expression", "name", "symbol", "function") 匹配并且如果它不直接匹配本地 refClass 字段名称则警告可能会出错?

【讨论】:

乍一看,这看起来很有前途!非常感谢!!

以上是关于在检索 S4 参考类的字段值时避免考虑封闭帧的主要内容,如果未能解决你的问题,请参考以下文章

未考虑 Java OpenCV VideoCapture 属性。需要避免最新帧的“当真”。多相机环境

SQL优化的方式

如何避免Kotlin暴露的N + 1查询问题。 (通过DAO的Reference.id.value字段获取值时)

在运行时决定返回类型是右值还是左值时,如何避免不必要的复制?

Elasticseach-强制字段仅索引,避免存储

glReadPixels 的 OpenGL DSA 等效项