引用类,选项卡完成和强制方法定义

时间:2012-09-22 11:01:04

标签: r s4 reference-class

我目前正在使用引用类编写包。我遇到过 阅读各种来源的问题:

Method initialisation in R reference classes

Can't reliably use RefClass methods in Snowfall

我收集是因为引用方法并非全部复制到每个对象 在课堂上,而不是在第一次访问时复制它们。

https://stat.ethz.ch/pipermail/r-devel/2011-June/061261.html

作为一个例子定义:

test <- setRefClass("TEST",
                fields = list( a = "numeric"),
                methods = list(
                   addone = function(){
                                        a <<- a+1
                                      },
                   initialize = function(){
                                            a <<- 1
                                          }
                              )
               )

example <- test$new()

所以示例是类TEST的新对象。在{中输入example$和标签 控制台提供

> example$
# example$.->a         example$.refClassDef example$.self        
# example$a            example$initialize 

因此方法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

所以现在addonefield以及show会显示为选项。

Martin Morgan建议在上述某个链接中强制定义方法。这个 运作良好

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()

所以现在tabbing给出了:

# > example$
# example$.->a         example$.refClassDef example$.self        
# example$a            example$addone       example$initialize  

我的一些课程有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()
Tab键现在给出:

# > 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     

虽然这有效但感觉有点笨拙。另外使用test$def@refMethods而不是getRefClass("TEST")$def@refMethods 感觉有点不对劲。有没有人以前处理过这个问题。

有没有更好的方法来解决问题?如果问题被过度提出,感谢任何建议和道歉。

3 个答案:

答案 0 :(得分:6)

我想知道你的目标是什么?功能名称显示标签完成?然后,它需要一个功能请求到R-devel邮件列表的帖子。使用usingMethods处理?setRefClass时更加优雅地处理原始方案。持续的黑客可能是

initialize = function(...) {
    methods <- getRefClass(class(.self))$methods()
    eval(parse(text=paste0(".self$", methods)))
    callSuper(...)
}

标签完成次数可以通过.DollarNames包中的utils自定义,所以

.DollarNames.TEST <- function(x, pattern)
    grep(pattern, getRefClass(class(x))$methods(), value=TRUE)

也许可以在类层次结构的基础上编写S3方法吗?

答案 1 :(得分:3)

我知道这是一个老问题但在Google上搜索refClass标签时它仍然是最重要的条目,所以我只是添加更新:

不要像Martin建议的那样在.DollarNames函数中使用grep,而是使用utils包中的findMatches,因为它可以更好地与不同的Rgui一起使用(grep会在点击标签时删除部分键入的名称)

.DollarNames.TEST <- function(x, pattern){
    utils:::findMatches(pattern, getRefClass(class(x))$methods())
}

这也是列表和data.frames

内部处理制表符的方式

答案 2 :(得分:1)

@Martin Morgan指出,这被称为标签完成。包rcompletion和更晚rcompgen的任务是实现这一目标。他们现在已转移到utils

rcompletion update

我查看了completion.R的代码以及我可以确定的utils:::.DollarNames.environment正在处理参考类的标签完成。

completion.R

重新定义该功能似乎实现了标签完成:

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(如果没有禁止)请参阅?assignInNamespace

  • 强制定义方法更为可取。