当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


R setClass 创建类定义


R语言 setClass 位于 methods 包(package)。

说明

创建一个类定义并返回一个生成器函数以从该类创建对象。典型的用法是这样的:

myClass <- setClass("myClass", slots= ...., contains =....)

其中第一个参数是新类的名称,如果提供,参数 slots=contains= 指定新类和新类应继承的现有类中的槽。对 setClass() 的调用通常可以在包的源代码中找到;加载包时,该类将在包的命名空间中定义。用类名指定生成器函数对用户来说很方便,但不是必需的。

用法

setClass(Class, representation, prototype, contains=character(),
         validity, access, where, version, sealed, package,
         S3methods = FALSE, slots)

参数

Class

类的字符串名称。

slots

新类中插槽的名称和类。该参数必须在调用中通过名称 slots= 提供,以便与不再推荐的其他参数向后兼容。

参数必须是带有名称属性的向量,名称是新类中插槽的名称。向量的每个元素指定一个现有的类;相应的槽必须来自该类或其子类。通常,这是命名类的字符向量。向量的元素作为类表示对象也是合法的,如 getClass 返回的那样。

作为限制情况,参数可以是未命名的字符向量;这些元素被视为插槽名称,并且所有插槽都具有不受限制的类 "ANY"

contains

一个向量,指定该类应继承的现有类。新类将具有超类的所有槽,对这些槽的类具有相同的要求。该参数必须在调用中通过名称 contains= 提供,以便与不再推荐的其他参数向后兼容。

请参阅“虚拟类”部分了解特殊超类 "VIRTUAL"

prototype, where, validity, sealed, package

这些论点目前是允许的,但或者它们不太可能有用,或者有首选的现代替代方案。

prototype :为该类中的槽提供默认数据的对象。更灵活的方法是为 initialize() 编写一个方法。

where:提供存储定义的环境。不应使用:对于出现在包源代码中的setClass() 的调用,定义将存储在包的命名空间中。

validity :为此类中的对象提供validity-checking 方法。为了使代码更清晰,请使用对 setValidity() 的单独调用。

sealed :如果 TRUE ,则类定义将被密封,以便对该类名再次调用 setClass 将失败。但加载命名空间后,定义会自动密封,因此不需要显式密封。

package :为类提供可选的包名称,但类属性应该是在其中分配类定义的包,默认情况下也是如此。

representation, access, version, S3methods

所有这些参数从 3.0.0 版本开始已弃用R并且应该避免.

representation 是从 S 继承的参数,其中包括 slotscontains ,但后两个参数的使用更清晰,建议使用。

包含 accessversion 是为了与 S-Plus 历史兼容,但会被忽略。

S3methods是一个标志,指示将编写涉及该类的old-style方法;现在被忽略了。

一个适合从类创建对象的生成器函数会以不可见的方式返回。对此函数的调用会生成对该类的new 的调用。该调用采用任意数量的参数,这些参数将传递给初始化方法。如果没有为该类或其超类之一定义 initialize 方法,则默认方法需要具有插槽之一名称的命名参数和来自所包含的类之一的对象的未命名参数。

通常,为了编程清晰起见,生成器函数会被分配类的名称。这不是必需的,类中的对象也可以直接从 new 生成。生成器函数的优点是调用稍微简单和清晰,并且调用将包含类的包名称(如果来自不同包的两个类具有相同名称,则消除任何歧义)。

如果该类是虚拟类,则尝试从生成器或 new() 生成对象将导致错误。

基本用途:槽和继承

除类名之外的两个基本参数是 slotscontains ,它们定义显式槽和继承(超类)。这些参数一起定义了该类的对象中的所有信息;即所有槽的名称以及每个槽所需的类。

类的名称决定哪些方法直接应用于该类的对象。超类信息指定通过继承间接应用哪些方法。方法选择中的继承请参见Methods_Details

类定义中的槽将是由 slots 直接指定的所有槽和所有包含的类中的所有槽的并集。只能有一个具有给定名称的插槽。类可以覆盖具有给定名称的槽的定义,但前提是新指定的类是继承类的子类。例如,如果包含的类有一个槽 a 和类 "ANY" ,则子类可以指定 a 和类 "numeric" ,但如果该槽的原始规范是类 "character" ,则新调用setClass 会产生错误。

不允许插槽名称 "class""Class"。还有其他具有特殊含义的插槽名称;这些名称以 "." 字符开头。为了安全起见,您应该定义自己的所有插槽,其名称以字母字符开头。

一些继承的类将被特殊对待——对象类型、S3 类和一些特殊情况——无论是直接继承还是间接继承。请参阅接下来的三节。

虚拟课程

存在无法为其创建实际对象的类,即虚拟类。

虚拟课堂最常见和最有用的形式是阶级联盟,在调用中定义的虚拟类setClassUnion()而不是调用给setClass()。此调用列出了会员联合的子类扩展了新类。在签名中使用类联合编写的方法可以与任何成员类中的对象一起使用。类联合可以包含其定义被密封的成员类,包括基本类R数据类型。

当仅提供 Class 参数(无槽或超类)或当 contains= 参数包含特殊类名 "VIRTUAL" 时,对 setClass() 的调用也将创建一个虚拟类。

在后一种情况下,虚拟类可能包含槽来提供一些常见行为,而无需完全定义对象 - 请参阅类traceable 作为示例。请注意,"VIRTUAL" 不会延续到子类;包含虚拟类的类本身并不自动是虚拟的。

从对象类型继承

除了包含其他 S4 类之外,类定义还可以包含 S3 类(请参阅下一节)或内置 R pseudo-class——其中一个R对象类型或特殊类型之一R伪类"matrix""array"。一个类最多可以直接或间接包含一种对象类型。当它出现时,包含的类确定该类的“data part”。这显示为pseudo-slot,".Data"和 可以被视为一个槽,但实际上确定该槽中对象的类型。

新类中的对象尝试继承所包含类型的内置行为。正常情况下R数据类型包括向量、函数和表达式,实现相对简单。对于任何物体x从课堂上,typeof(x)将是包含的基本类型;和一个特殊的pseudo-slot,.Data,将与相应的类别一起显示。请参阅"numWithId"下面的例子。

类也可以继承自 "vector""matrix""array" 。这些对象的数据部分可以是任何矢量数据类型。

对于不包含这些类型或类之一的任何类的对象, typeof(x) 将是 "S4"

一些R数据类型的行为不正常,因为它们是非本地引用或其他不重复的对象。示例包括对应于类的示例"environment","externalptr", 和"name"。这些不能是具有用户定义类(S4 或 S3)的对象的类型,因为设置属性会覆盖所有上下文中的对象。可以通过将继承的对象存储在保留槽中的间接机制来定义从此类类型继承的类,".xData"。请参阅类的示例"stampedEnv"以下。来自此类的对象确实不是有一个".Data"pseudo-slot。

对于大多数计算,这些类的行为是透明的,就好像它们直接从异常类型继承一样。 S3 方法调度和相关的 as. 类型 () 函数应该正常运行,但直接使用对象类型的代码则不会。例如, as.environment(e1) 将按预期与 "stampedEnv" 类一起工作,但 typeof(e1)"S4"

从S3类继承

Old-style S3 类没有正式定义。当对象的类属性包含被视为类名的字符串时,对象就是“from”类。

将此类类与正式类和方法一起使用必然是一件有风险的事情,因为无法保证对象的内容或继承方法的一致性。鉴于此,仍然可以定义一个从 S3 类继承的类,前提是该类已注册为旧类(请参阅 setOldClass )。

从广义上讲,S3 和 S4 方法分派都尝试在任一系统中对继承表现得明智。给定一个 S4 对象,S3 方法调度和 inherits 函数应使用 S4 继承信息。给定一个 S3 对象,S4 泛型函数将使用 S3 继承调度 S4 方法,前提是已通过 setOldClass 声明了继承。有关详细信息,请参阅setOldClass 和参考文献的第 10.8 节。

课程和套餐

类定义通常属于包(但也可以在全局环境中定义,通过评估命令行上或源自命令行的文件中的表达式)。相应的包名称是类定义的一部分;也就是说,classRepresentation 对象的一部分保存该定义。因此,对于大多数用途来说,两个具有相同名称的类可以存在于不同的包中。

当在 setClass 调用中为槽或超类提供类名时,将从当前包的命名空间中查找相应的类定义,假设相关调用直接出现在包的源代码中,因为它应该避免歧义。类定义必须已在此包中、包的DESCRIPTIONNAMESPACE 文件的导入指令中或在方法包定义的基本类中定义。 (‘methods’ 包必须包含在任何使用 S4 方法和类的包的导入指令中,以满足 "CMD check" 实用程序的要求。)

如果一个包从不同的包导入两个同名的类,则 name 参数的 packageSlot 需要设置为特定类的包名称。这种情况应该很少见。

例子


## A simple class with two slots
track <- setClass("track", slots = c(x="numeric", y="numeric"))
## an object from the class
t1 <- track(x = 1:10, y = 1:10 + rnorm(10))

## A class extending the previous, adding one more slot
trackCurve <- setClass("trackCurve",
		slots = c(smooth = "numeric"),
		contains = "track")

## an object containing a superclass object
t1s <- trackCurve(t1, smooth = 1:10)

## A class similar to "trackCurve", but with different structure
## allowing matrices for the "y" and "smooth" slots
setClass("trackMultiCurve",
         slots = c(x="numeric", y="matrix", smooth="matrix"),
         prototype = list(x=numeric(), y=matrix(0,0,0),
                          smooth= matrix(0,0,0)))

## A class that extends the built-in data type "numeric"

numWithId <- setClass("numWithId", slots = c(id = "character"),
         contains = "numeric")

numWithId(1:3, id = "An Example")

## inherit from reference object of type "environment"
stampedEnv <- setClass("stampedEnv", contains = "environment",
                       slots = c(update = "POSIXct"))
setMethod("[[<-", c("stampedEnv", "character", "missing"),
   function(x, i, j, ..., value) {
       ev <- as(x, "environment")
       ev[[i]] <- value  #update the object in the environment
       x@update <- Sys.time() # and the update time
       x})


e1 <- stampedEnv(update = Sys.time())

e1[["noise"]] <- rnorm(10)


参考

Chambers, John M. (2016) Extending R, Chapman & Hall. (Chapters 9 and 10.)

也可以看看

Classes_Details 用于类的一般讨论,Methods_Details 用于方法的类似讨论,makeClassRepresentation

相关用法


注:本文由纯净天空筛选整理自R-devel大神的英文原创作品 Create a Class Definition。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。