7

我目前正在使用参考类编写一个包。我在阅读各种资料时遇到了一个问题:

R 参考类中的方法初始化

无法在 Snowfall 中可靠地使用 RefClass 方法

我认为是因为引用方法并非全部复制到类中的每个对象,而是在第一次访问时被复制。

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

所以 example 是 class 的一个新对象TESTexample$在控制台中键入和制表符给出

> 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

所以现在addonefieldshow作为选项呈现。

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

所以现在制表符给出:

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

制表符现在给出:

# > 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这样,感觉有点不对劲。以前有没有人处理过这个问题。

有没有更好的方法来解决问题?如果问题过于冗长,感谢您的任何建议和道歉。

4

3 回答 3

6

我想知道你的目标是什么?功能名称与选项卡完成一起显示?那么值得在 R-devel 邮件列表中发布一个功能请求。原始场景的处理更优雅,usingMethods?setRefClass. 持续的黑客攻击可能是

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

选项卡完成可以通过.DollarNamesutils包中自定义,所以

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

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

于 2012-09-22T15:59:35.900 回答
3

我知道这是一个老问题,但在谷歌上搜索 refClass 选项卡完成时它仍然是最重要的条目,所以我只添加一个更新:

不要像 Martin 建议的那样在 .DollarNames 函数中使用 grep,而是使用 utils 包中的 findMatches,因为它可以更好地与不同的 Rgui 配合使用(grep 将在点击选项卡时删除您部分输入的名称)

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

这也是列表和 data.frames 内部处理选项卡完成的方式

于 2014-11-03T09:50:38.840 回答
1

@Martin Morgan 指出这被称为制表符完成。该软件包rcompletion和后来rcompgen的任务是实现这一目标。他们现在已经搬到utils.

r完成更新

我查看了代码,completion.R并从中可以确定utils:::.DollarNames.environment正在处理参考类的选项卡完成。

完成.R

重新定义函数似乎实现了tab补全:

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

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

于 2012-09-23T01:51:46.840 回答