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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。