【发布时间】: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:很好,谢谢!
标签: r oop pass-by-reference s4 reference-class