在保留继承的同时注册R6类的S4等价物 实际问题

在保留继承的同时注册R6类的S4等价物 实际问题,r,methods,namespaces,s4,r6,R,Methods,Namespaces,S4,R6,当所有类都需要存在于包的名称空间中时(而不是在GlobalEnv中),如何将相互继承的一组R6类转换为S4类,同时保留继承结构 细节 如果R6类已在.GlobalEnv中定义(就像使用source()进行寻源一样),并且setOldClass()也使用where=.GlobalEnv调用,那么一切都可以正常工作 但是,当R6类在包的命名空间中定义时(比如调用devtools::load_all()),我无法让它工作: 在.GlobalEnv中定义R6类: Object <- R6Class

当所有类都需要存在于包的名称空间中时(而不是在
GlobalEnv
中),如何将相互继承的一组R6类转换为S4类,同时保留继承结构

细节 如果R6类已在
.GlobalEnv
中定义(就像使用
source()
进行寻源一样),并且
setOldClass()
也使用
where=.GlobalEnv
调用,那么一切都可以正常工作

但是,当R6类在包的命名空间中定义时(比如调用
devtools::load_all()
),我无法让它工作:

.GlobalEnv
中定义R6类:

Object <- R6Class("Object", portable = TRUE, public = list(
  foo = function() "foo")
)
Api <- R6Class("Api", inherit = Object, portable = TRUE,
  public = list(bar = function() "bar")
)
Module <- R6Class("Module", inherit = Api, portable = TRUE,
  public = list(fooBar = function() "fooBar")
当R6类在包的名称空间中定义时(如使用
devtools::load_all()
而不是
source()
“寻源”时),我假设我需要通过提供一个显式的
where

setOldClass(c("Object", "R6"))
setOldClass(c("Api", "Object"))
setOldClass(c("Module", "Api"))
where <- if ("package:r6.s4" %in% search()) {
  as.environment("package:r6.s4")
} else {
  .GlobalEnv
}
try(setOldClass(c("Object", "R6"), where = where))
try(setOldClass(c("Api", "Object"), where = where))
try(setOldClass(c("Module", "Api"), where = where))

在哪里我想我找到了答案

经验教训
  • setOldClass(c(“模块”、“Api”)
    失败的原因是因为包
    Rcpp
    定义了一个具有相同名称的类

    require("R6")
    > getClass("Module")
    Class "Module" [package "Rcpp"]
    
    Slots:
    
      Name:       .xData
    Class: environment
    
    Extends: 
      Class ".environment", directly
    Class "environment", by class ".environment", distance 2, with explicit coerce
    Class "refObject", by class ".environment", distance 3, with explicit coerce
    
  • 调用
    setOldClass()
    的最佳位置似乎在
    .onAttach()
    内,因为在此阶段包已完全加载,因此存在
    where
    参数可以指向的命名空间环境

    .onAttach <- function(libname, pkgname) {
      where <- as.environment("package:r6.s4")
      clss <- list(
        c("Object", "R6"),
        c("Api", "Object"),
        c("Module2", "Api")
      )
      sapply(clss, function(cls) {
        try(setOldClass(cls, where = where))
      })
    }
    
  • 我喜欢
    R6
    依赖于实际的生成器对象的方法,而不仅仅是类名很多,因为它使您能够使用
    ,从而使类与所有其他包组件一样有组织。但不幸的是,当通过
    setOldClass()
    为它们注册S4等价物时,这种范例似乎丢失了。这种情况让我又回到了我以前的抱怨,那就是——
    *叹气*


  • 对于那些对我的试错过程的细节感兴趣的人来说:我试图把这个包变成一种自我参考。检查文件,以及一些关于如何检查和处理名称冲突的原型代码。

    我也有类似的情况。但是在我的包中,我为包中定义的类编写了一些方法(例如,在您的示例中,
    Api
    Module2
    ),用于在其他包中定义的通用S4函数(例如,
    sp::coordinates
    ),使用类似的东西:
    setMethod('coordinates',signature='Api'){…
    )。这导致加载包时出错,因为类
    Api
    R
    解析新方法时未注册。
     .onAttach <- function(libname, pkgname) {
      where <- as.environment("package:r6.s4")
      clss <- list(
        c("Object", "R6"),
        c("Api", "Object"),
        c("Module2", "Api")
      )
      sapply(clss, function(cls) {
        idx <- sapply(cls, isClass)
        try(sapply(cls[idx], removeClass, where = where))
        try(setOldClass(cls, where = where))
      })      
    }