我想在另一个引用类中使用自定义引用类,但是此代码失败:

nameClass <- setRefClass("nameClass", fields = list(first = "character",
                                                last = "character"),
                     methods = list(
                       initialize = function(char){
                         chunks <- strsplit(char,"\\.")
                         first <<- chunks[[1]][1]
                         last <<- chunks[[1]][2]
                       },
                       show = function(){
                         cat("Special Name Class \n:")
                         cat("First Name:")
                         methods::show(first)
                         cat("Last Name:")
                         methods::show(last)
                       }
                       ))
# this works fine
nameClass$new("tyler.durden")

当我尝试添加另一个具有nameClass类字段的类时,无法启动该类。
personClass <- setRefClass("personClass", fields = list(fullname = "nameClass",
                                                    occupation = "character"),
                       methods = list(
                         initialize = function(Obj){
                           nm  <- deparse(substitute(Obj))
                           fullname <<- nameClass$new(nm)
                           occupation <<- Obj
                         }))

这只是返回:
 Error in strsplit(char, "\\.") :
 argument "char" is missing, with no default

我可以想像一个解决方案,其中nameClass是S4类,但是我读了点东西后就有点害怕混合使用S4和引用类。我想缺少一些东西吗?还是我想更准确地定义此特定名称字段而不是仅使用“字符”时,我是否应该简单地使用S4类?

我还发现this thread的标题很有希望,但不知道该如何解决我的问题。

最佳答案

这是S4系统中一个常见问题的变体,在继承中,为使继承起作用,必须使用零参数对new进行调用。这是由于实现继承的方式所致,在该方法中,实例化了基类,然后使用派生类中的值填充基类。要实例化基类,需要创建不带任何参数的基类。您有问题的说明

> nameClass()
Error in .Internal(strsplit(x, as.character(split), fixed, perl, useBytes)) :
  'x' is missing

解决方案是在您的initialize方法中提供默认参数
initialize=function(char=charcter()) { <...> }

或以其他方式安排(例如,通过测试missing(char)主体中的initialize)对构造函数的无参数调用。

可能的编程最佳实践将要求initialize方法采用...参数,并且其主体中具有callSuper(),以便派生类可以利用基类(例如,字段分配)功能。为了避免无名参数的无意匹配问题,我认为签名可能应该最终围绕一个看起来像这样的模板构建
initialize(..., char=character()) { callSuper(...) }

此方案依赖于对“空” nameClass的适当定义。以下内容可能有太多的见解和观点变化,因此无法立即使用,但是...很有诱惑力将nameClass视为数据帧中的“行”,但是最好考虑一下(因为R在向量上效果最好)它作为描述列。考虑到这一点,“空” nameClass的合理表示形式是firstlast字段的长度均为0。
nameClass <- setRefClass("nameClass",
    fields = list(first = "character", last = "character"),
    methods = list(
      initialize = function(..., char=character()){
          if (length(char)) {
              names <- strsplit(char, ".", fixed=TRUE)
              .first <- vapply(names, "[[", character(1), 1)
              .last <- vapply(names, "[[", character(1), 2)
          } else {
              .first <- character()
              .last <- character()
          }
          callSuper(..., first=.first, last=.last)
      }, show = function(){
          .helper <- function(x)
              sprintf("%s%s", paste(sQuote(head(x)), collapse=", "),
                      if (length(x) > 6) ", ..." else "")
          cat("Special Name Class (n = ", length(first), ")\n", sep="")
          cat("First names:", .helper(first), "\n")
          cat("Last names:", .helper(last), "\n")
      }))

用像这样的测试用例
> nameClass()
Special Name Class (n = 0)
First names:
Last names:
> nameClass(char="Paul.Simon")
Special Name Class (n = 1)
First names: 'Paul'
Last names: 'Simon'
> nameClass(char=c("Paul.Simon", "Frank.Sinatra"))
Special Name Class (n = 2)
First names: 'Paul', 'Frank'
Last names: 'Simon', 'Sinatra'
> nameClass(char=paste(LETTERS, letters, sep="."))
Special Name Class (n = 26)
First names: 'A', 'B', 'C', 'D', 'E', 'F', ...
Last names: 'a', 'b', 'c', 'd', 'e', 'f', ...

派生类可以定义为
personClass <- setRefClass("personClass",
    fields = list(fullname = "nameClass", occupation = "character"),
    methods = list(
      initialize = function(..., fullname=nameClass(),
                            occupation=character()) {
          callSuper(..., fullname=fullname, occupation=occupation)
      }))

用像这样的测试用例
personClass()
personClass(fullname=nameClass())
personClass(fullname=nameClass(), occupation=character())
personClass(fullname=nameClass(char="some.one"), occupation="job")

09-25 15:41