R 引用类、制表符完成和强制方法定义
我目前正在使用引用类编写一个包。我遇到过 这是一个通过阅读各种来源得出的结论: 我收集是因为引用方法并不是全部复制到每个对象 在类中,它们在第一次访问时被复制 例如,定义:R 引用类、制表符完成和强制方法定义,r,s4,reference-class,R,S4,Reference Class,我目前正在使用引用类编写一个包。我遇到过 这是一个通过阅读各种来源得出的结论: 我收集是因为引用方法并不是全部复制到每个对象 在类中,它们在第一次访问时被复制 例如,定义: test <- setRefClass("TEST", fields = list( a = "numeric"), methods = list( addone = function(){
test <- setRefClass("TEST",
fields = list( a = "numeric"),
methods = list(
addone = function(){
a <<- a+1
},
initialize = function(){
a <<- 1
}
)
)
example <- test$new()
因此,方法addone
不作为选项提供。可供
但是,请致电:
example$addone()
现在,选项卡再次显示
# >
# > example
# Reference class object of class "TEST"
# Field "a":
# [1] 2
# > example$
# example$.->a example$.refClassDef example$.self
# example$a example$addone example$field
# example$initialize example$show
现在,addone
和field
和show
作为选项显示
MartinMorgan建议强制在上述链接之一中定义方法。这
效果很好
test <- setRefClass("TEST",
fields = list( a = "numeric"),
methods = list(
addone = function(){
a <<- a+1
},
initialize = function(){
a <<- 1
.self$addone #force definition
}
)
)
example <- test$new()
我的一些类有30多个方法,所以我希望尽可能简洁地完成这项工作。
我定义了:
test <- setRefClass("TEST",
fields = list( a = "numeric"),
methods = list(
addone = function(){
a <<- a+1
},
initialize = function(){
a <<- 1
eval(parse(text=paste0('.self$',ls(test$def@refMethods))))
}
)
)
example <- test$new()
虽然这样做有效,但感觉有点笨拙。还有测试$def@refMethods使用
而不是getRefClass(“测试”)$def@refMethods
以便
感觉有点不对劲。以前有人处理过这个问题吗
有没有更好的解决方案?如果问题太长,谢谢你的建议和道歉。我想知道你的目标是什么?函数名是否随选项卡完成一起显示?那么就值得在R-devel邮件列表中发布一个功能请求。如
?setRefClass
中所述,使用方法可以更优雅地处理原始场景。持续的黑客攻击可能是
initialize = function(...) {
methods <- getRefClass(class(.self))$methods()
eval(parse(text=paste0(".self$", methods)))
callSuper(...)
}
也许可以在类层次结构的基础上为此编写一个S3方法?@Martin Morgan指出,这被称为制表符完成。包rcompletion
和后来的rcompgen
的任务就是实现这一点。它们现在已移动到utils
我查看了completion.R
的代码,根据我所能确定的utils::.DollarNames.environment
正在处理引用类的制表符完成
重新定义该函数似乎可以实现制表符的完成:
assignInNamespace( x = ".DollarNames.environment",
function(x, pattern = "") {
y <- NULL
if(isS4(x) && !is.null(x[['.refClassDef']])){
if(.hasSlot(x$.refClassDef,'refMethods')){
y<-x$.refClassDef@refMethods
y<-ls(y, all.names = TRUE, pattern = pattern)
}
}
x<-ls(x, all.names = TRUE, pattern = pattern)
unique(c(x,y))
}
,ns = "utils")
assignInNamespace(x=“.DollarNames.environment”,
函数(x,pattern=“”){
y我知道这是一个老问题,但在google上搜索refClass tab completion时,它仍然是最重要的条目,因此我只需添加一个更新:
不要像Martin建议的那样在.DollarNames函数中使用grep,而是使用utils包中的findMatches,因为它可以更好地处理不同的Rgui(grep会在点击tab时删除部分键入的名称)
.DollarNames.TEST谢谢你,这比我的解决方案非常有用,而且更优雅。我也不知道它被称为tab completion。了解这个术语使我能够在UTIL中找到相关的包。使用参考类完成tab是我的目标,我将编辑问题标题以更好地反映这一点。这似乎很有希望。Wou添加.DollarNames.envRefClass是的,这将是一个坏主意--您将更改所有引用类的行为,而不仅仅是您自己的引用类。也许一些人喜欢它的当前行为,也许方法将在将来某个日期实现超级复制程序。DollarNames.envRefClass
,而您早已忘记的方法将然后覆盖它。正确的做法是在R-devel上把它作为一个功能请求,特别是现在你至少有一个工作原型来说明你认为合适的行为。Martin Morgan感谢你的时间和专业知识。我将向R-devel发布一个功能请求。实际上,。DollarNames
是一个S3通用因此,您可以在上面编写S3方法;我在回答中对此进行了说明。
# > example$
# example$.->a example$.refClassDef example$.self
# example$a example$addone example$callSuper
# example$copy example$export example$field
# example$getClass example$getRefClass example$import
# example$initFields example$initialize example$show
# example$trace example$untrace
initialize = function(...) {
methods <- getRefClass(class(.self))$methods()
eval(parse(text=paste0(".self$", methods)))
callSuper(...)
}
.DollarNames.TEST <- function(x, pattern)
grep(pattern, getRefClass(class(x))$methods(), value=TRUE)
assignInNamespace( x = ".DollarNames.environment",
function(x, pattern = "") {
y <- NULL
if(isS4(x) && !is.null(x[['.refClassDef']])){
if(.hasSlot(x$.refClassDef,'refMethods')){
y<-x$.refClassDef@refMethods
y<-ls(y, all.names = TRUE, pattern = pattern)
}
}
x<-ls(x, all.names = TRUE, pattern = pattern)
unique(c(x,y))
}
,ns = "utils")
.DollarNames.TEST <- function(x, pattern){
utils:::findMatches(pattern, getRefClass(class(x))$methods())
}