找到你要的答案

Q:how to define a dynamic constructor in R for s4 object

Q:如何定义在R S4对象动态构造函数

Is it possible to define a dynamic constructor in R for a S4 object? By dynamic I mean the following:

firstClass <- setClass(Class = "firstClass",slots = c(Name = "character", ID = "numeric"))

Now I would like to define a constructor which is smart, i.e. it checks what arguments where provided by the function call and creates a object of calss "firstClass" by setting the slots do default or the provided argument. For example

firstClass <- function(Name, ID){
  if(missing(Name) & missing(ID)){
    return(new(Class = firstClass))
  }
  if(missing(Name) & !missing(ID)){
    return(new(Class = firstClass,ID = ID))
  }
  if(!missing(Name) & missing(ID)){
    return(new(Class,Name = Name))
  }
  if(!missing(Name) & !missing(ID)){
    return(new(Class, Name = Name, ID = ID))
  }
}

Clearly some sanity checks should be done as well. This constructor does exactly what I want, depending of the call it constructs an object. However, for an simple class (few slots) this is ok, but with more slots the complexity grows. So I'm wondering if there is an elegant way to do it.

它可以定义为S4对象R动态构造函数?我的意思是以下:

firstClass <- setClass(Class = "firstClass",slots = c(Name = "character", ID = "numeric"))

现在我想定义一个构造函数,是聪明的,即它检查哪些参数在函数调用和创建一个对象的类“一流”通过设置槽做违约或所提供的参数。例如

firstClass <- function(Name, ID){
  if(missing(Name) & missing(ID)){
    return(new(Class = firstClass))
  }
  if(missing(Name) & !missing(ID)){
    return(new(Class = firstClass,ID = ID))
  }
  if(!missing(Name) & missing(ID)){
    return(new(Class,Name = Name))
  }
  if(!missing(Name) & !missing(ID)){
    return(new(Class, Name = Name, ID = ID))
  }
}

显然,也应该做一些精神检查。这个构造函数完全按照我想要的,根据它构造对象的调用。然而,对于一个简单的类(少数插槽),这是确定的,但与更多的插槽的复杂性增长。所以我想知道是否有一个优雅的方式来做。

answer1: 回答1:

Use a prototype to provide sane default values

.firstClass <-
    setClass(Class = "firstClass",
             representation = representation(
               Name = "character",
               ID = "integer"),
             prototype=c(ID=0L))

Use default values as arguments in the constructor, as well as coercion to appropriate types if necessary

firstClass <- function(Name=character(), ID=0L)
    .firstClass(Name=Name, ID=as.integer(ID))

(.firstClass is a light wrapper around new("firstClass", ...), to me it provides a little separation between the implementation details (calling new() to construct a class) and the interface to class construction. firstClass() is a second and more useful layer, explosing necessary arguments for object construction to the user in a way that does not require knowledge of the underlying class). Enforce 'sanity checks' in a validity method

setValidity("firstClass", function(object) {
    msg <- NULL
    if (length(object@ID) != 1)
        msg <- c(msg, "ID must be length 1")
    else if (object@ID < 0)
        msg <- c(msg, "ID must be >= 0")
    if (is.null(msg)) TRUE else msg
})

使用原型提供健全的默认值

.firstClass <-
    setClass(Class = "firstClass",
             representation = representation(
               Name = "character",
               ID = "integer"),
             prototype=c(ID=0L))

在构造函数中使用默认值作为参数,如果必要的话,对适当类型强制

firstClass <- function(Name=character(), ID=0L)
    .firstClass(Name=Name, ID=as.integer(ID))

(。一流是围绕新轻型包装(“一流”,…),给我提供了实现细节之间的小分离(称new()构造一个类的接口)和班级建设。firstclass()是第二和更有用的层,来揭露的必要参数为对象构建的一种方式,不需要对基础类知识的用户)。在有效性方法中执行“健全检查”

setValidity("firstClass", function(object) {
    msg <- NULL
    if (length(object@ID) != 1)
        msg <- c(msg, "ID must be length 1")
    else if (object@ID < 0)
        msg <- c(msg, "ID must be >= 0")
    if (is.null(msg)) TRUE else msg
})
r  s4