setIs
位于 methods
包(package)。 说明
setIs
是 setClass
的 contains=
参数的显式替代方案。只需要通过明确的测试或强制来建立关系。这些都没有被证明有太大的实用值,因此在应用中应该不太需要这个函数。
如果编程目标是定义将一类对象转换为另一类对象的方法,则通常更好的做法是调用 setAs()
,这需要显式完成转换。
用法
setIs(class1, class2, test=NULL, coerce=NULL, replace=NULL,
by = character(), where = topenv(parent.frame()), classDef =,
extensionObject = NULL, doComplete = TRUE)
参数
class1, class2 |
要检查定义的 |
coerce, replace |
可选地提供函数以将对象强制为 |
test |
通过提供此函数来定义条件关系。不鼓励条件关系,并且不将其包含在选择方法中。请参阅下面的详细信息部分。 其余参数供内部使用和/或通常被省略。 |
extensionObject |
|
doComplete |
当 |
by |
在对 |
where |
在对 |
classDef |
|
细节
安排一个类从另一个类继承是编程中的一个关键工具。在R,共有三种基本技术,前两种提供所谓的“simple”继承,首选形式:
-
通过调用
setClass
中的contains=
参数。这是而且应该是最常见的机制。它安排新类包含现有类的所有结构,特别是指定了相同类的所有槽。生成的类扩展被定义为simple
,对方法定义具有重要影响(请参阅下面有关此主题的部分)。 -
使
class1
成为虚拟类的子类,可以通过调用setClassUnion
使子类成为新类联合的成员,或者通过调用setIs
将类添加到现有类联合或作为现有虚拟类的新子类。无论哪种情况,都意味着为类联合或其他超类定义的方法对于子类都可以正确工作。这可能取决于子类结构中的某些相似性,或者简单地表明超类方法是根据适用于所有子类的通用函数来定义的。这些关系通常也很简单。 -
供应
coerce
和replace
论点setAs
.R允许任意继承关系,使用相同的机制通过调用来定义强制方法setAs
。两者的区别很简单setAs
需要调用as
进行转换,而在调用之后setIs
,对象将自动转换为超类。自动特性是危险的部分,主要是因为它会导致子类潜在继承的方法不起作用。请参阅下面有关继承的部分。如果所涉及的两个类实际上并未继承大量方法,如下面的第一个示例所示,那么危险可能相对较小。
如果超类继承了子类仅具有默认或远程继承方法的方法,则更有可能出现问题。在这种情况下,一般建议改用
setAs
机制,除非有强有力的反驳理由。否则,准备重写一些继承的方法。
考虑到这一点,本节的其余部分说明了将 coerce=
和 replace=
参数提供给 setIs
时会发生的情况。
coerce
和 replace
参数是定义如何将 class1
对象强制为 class2
以及如何替换与 class2
对应的子类对象部分的函数。其中第一个是一个参数的函数,应该是 from
,第二个参数是两个参数( from
, value
)。有关详细信息,请参阅下面有关强制函数的部分。
当指定 by
时,强制过程首先强制到此类,然后强制到 class2
。您不太可能直接使用 by
参数,但它用于定义有关类的缓存信息。
setIs
返回(不可见)的值是 class1
的修订后的类定义。
强制、替换和测试函数
coerce
参数是将 class1
对象转换为 class2
对象的函数。 replace
参数是两个参数的函数,它修改 class1
对象(第一个参数)以替换其对应于 class2
的部分(作为第二个参数 value
提供)。然后它返回修改后的对象作为调用的值。换句话说,它充当实现表达式 as(object, class2) <- value
的替换方法。
考虑 coerce
和 replace
函数的最简单方法是考虑通常意义上的 class1
包含 class2
的情况,包括第二类的槽。 (重复一遍,在这种情况下,您不会调用 setIs
,但类比显示了调用时会发生什么。)
在这种情况下,coerce
函数只会通过从 class1
对象中提取相应的槽来创建 class2
对象。 replace
函数将替换 class1
对象中与 class2
对应的槽,并返回修改后的对象作为其值。
有关这些函数的更多讨论,请参阅 setAs
函数的文档。 (不幸的是,该函数的参数 def
对应于此处的参数 coerce
。)
如果将函数作为 test
参数提供,则继承关系也可以是有条件的。这应该是一个只有一个参数的函数,根据提供的对象是否满足关系 is(object, class2)
返回 TRUE
或 FALSE
。一般来说,不鼓励类之间的条件关系,因为它们需要针对每个对象进行计算来确定其有效性。它们不能像普通关系那样有效地应用,并且往往会使使用它们的代码更难以解释。注意:条件继承不用于分派方法。条件超类的方法不会被继承。相反,应该为子类定义一个方法来测试条件关系。
继承方法
为特定签名(与函数的一个或多个形式参数匹配的类)编写的方法自然会假设与参数相对应的对象可以被视为来自相应的类。这些对象将具有类的所有插槽和可用方法。
选择和分派方法的代码可确保此假设是正确的。如果继承是 “simple”,即通过在调用 setClass
时使用一次或多次 contains=
参数来定义,则通常不需要额外的工作。类是从超类继承的,具有相同的定义。
当通过对 setIs
的通用调用来定义继承时,需要额外的计算。这种形式的继承意味着子类不仅包含超类的槽,而且需要显式调用强制和/或替换方法。为了确保正确计算,在计算方法体之前,通过调用 as
来补充继承的方法。
在这种情况下生成的对 as
的调用具有参数 strict = FALSE
,这意味着只要它具有所有适当的槽,就可以在转换后的对象中保留额外的信息。 (正是这个选项允许使用简单的子类对象而无需进行任何更改。)当您编写强制方法时,您可能希望利用该选项。
通过非简单扩展继承的方法可能会导致歧义或意外选择。如果 class2
是一个只有几个适用方法的专用类,则创建继承关系可能对 class1
的行为影响不大。但如果 class2
是一个有很多方法的类,你可能会发现你现在为 class1
继承了一些不需要的方法,在某些情况下,无法继承预期的方法。在下面的第二个示例中,可能会假设来自类 "factor"
的非简单继承通过该类继承 S3 方法。但 S3 类是不明确的,实际上是 "character"
而不是 "factor"
。
对于某些泛型函数,由非简单扩展继承的方法或者已知为无效,或者很可能无效,因此已定义泛型函数以排除此类继承。例如initialize
方法必须返回目标类的对象;如果扩展很简单,这很简单,因为没有对参数对象进行任何更改,但本质上是不可能的。因此,泛型函数坚持只对继承进行简单的扩展。有关机制,请参阅 setGeneric
的 simpleInheritanceOnly
参数。您可以在定义新的通用函数时使用此机制。
如果您遇到允许非简单继承的函数的问题,有两种基本选择。或者退出 setIs
调用,并接受由 setAs
调用定义的显式强制;或者,定义涉及 class1
的显式方法来覆盖不良的继承方法。当出现严重问题时,第一选择更安全。
例子
## Two examples of setIs() with coerce= and replace= arguments
## The first one works fairly well, because neither class has many
## inherited methods do be disturbed by the new inheritance
## The second example does NOT work well, because the new superclass,
## "factor", causes methods to be inherited that should not be.
## First example:
## a class definition (see \link{setClass} for class "track")
setClass("trackCurve", contains = "track",
slots = c( smooth = "numeric"))
## 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 = structure(list(), x=numeric(), y=matrix(0,0,0),
smooth= matrix(0,0,0)))
## Automatically convert an object from class "trackCurve" into
## "trackMultiCurve", by making the y, smooth slots into 1-column matrices
setIs("trackCurve",
"trackMultiCurve",
coerce = function(obj) {
new("trackMultiCurve",
x = obj@x,
y = as.matrix(obj@y),
smooth = as.matrix(obj@smooth))
},
replace = function(obj, value) {
obj@y <- as.matrix(value@y)
obj@x <- value@x
obj@smooth <- as.matrix(value@smooth)
obj})
## Second Example:
## A class that adds a slot to "character"
setClass("stringsDated", contains = "character",
slots = c(stamp="POSIXt"))
## Convert automatically to a factor by explicit coerce
setIs("stringsDated", "factor",
coerce = function(from) factor(from@.Data),
replace= function(from, value) {
from@.Data <- as.character(value); from })
ll <- sample(letters, 10, replace = TRUE)
ld <- new("stringsDated", ll, stamp = Sys.time())
levels(as(ld, "factor"))
levels(ld) # will be NULL--see comment in section on inheritance above.
## In contrast, a class that simply extends "factor"
## has no such ambiguities
setClass("factorDated", contains = "factor",
slots = c(stamp="POSIXt"))
fd <- new("factorDated", factor(ll), stamp = Sys.time())
identical(levels(fd), levels(as(fd, "factor")))
参考
Chambers, John M. (2016) Extending R, Chapman & Hall. (Chapters 9 and 10.)
相关用法
- R setOldClass 注册旧式 (S3) 类和继承
- R setGroupGeneric 创建函数的组通用版本
- R setClass 创建类定义
- R setGeneric 创建函数的通用版本
- R setAs 将对象强制为类的方法
- R setMethod 创建并保存方法
- R setClassUnion 定义为其他类的联合的类
- R setLoadActions 设置包加载操作
- R selectSuperClasses 类的超类(特定类型)
- R showMethods 显示指定函数或类的所有方法
- R slot 正式类对象中的槽
- R show 显示对象
- R as 强制对象属于某个类
- R language-class 表示未评估语言对象的类
- R className 类名包含对应的包
- R BasicClasses 基本数据类型对应的类
- R callGeneric 从方法调用当前通用函数
- R findClass 查找类定义
- R ReferenceClasses 具有按引用处理的字段的对象(OOP 样式)
- R MethodsList 方法列表对象
- R StructureClasses 基本结构对应的类
- R getMethod 获取或测试方法的定义
- R S4groupGeneric S4组通用函数
- R methodUtilities 用于方法和 S-Plus 兼容性的实用函数
- R getClass 获取类定义
注:本文由纯净天空筛选整理自R-devel大神的英文原创作品 Specify a Superclass Explicitly。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。