當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


R setIs 顯式指定超類


R語言 setIs 位於 methods 包(package)。

說明

setIssetClasscontains= 參數的顯式替代方案。隻需要通過明確的測試或強製來建立關係。這些都沒有被證明有太大的實用值,因此在應用中應該不太需要這個函數。

如果編程目標是定義將一類對象轉換為另一類對象的方法,則通常更好的做法是調用 setAs() ,這需要顯式完成轉換。

用法

setIs(class1, class2, test=NULL, coerce=NULL, replace=NULL,
      by = character(), where = topenv(parent.frame()), classDef =,
      extensionObject = NULL, doComplete = TRUE)

參數

class1, class2

要檢查定義的 is 關係的類的名稱,或者(更有效)類的類定義對象。

coerce, replace

可選地提供函數以將對象強製為 class2 ,並更改對象以使 is(object, class2)value 相同。請參閱下麵的詳細信息部分。

test

通過提供此函數來定義條件關係。不鼓勵條件關係,並且不將其包含在選擇方法中。請參閱下麵的詳細信息部分。

其餘參數供內部使用和/或通常被省略。

extensionObject

test, coerce, replace, by 參數的替代方案;類 SClassExtension 中說明關係的對象。 (用於內部調用。)

doComplete

TRUE 時,類定義也將通過間接關係進行擴充。 (用於內部調用。)

by

在對 setIs 的調用中,中間類的名稱。強製將首先強製到此類,然後從那裏強製到目標類。 (中間強製轉換必須有效。)

where

在對 setIs 的調用中,存儲定義關係的元數據的位置。默認值是來自會話頂層的調用或在那裏評估的源文件的全局環境。當調用發生在包源中文件的頂層時,默認值將是包的命名空間或環境。其他用途很棘手,通常不是一個好主意,除非您真的知道自己在做什麽。

classDef

class 的可選類定義,在類的初始定義期間通過調用 setClass 調用 setIs 時內部需要。不要使用這個論點,除非你真的知道為什麽要這樣做。

細節

安排一個類從另一個類繼承是編程中的一個關鍵工具。在R,共有三種基本技術,前兩種提供所謂的“simple”繼承,首選形式:

  1. 通過調用 setClass 中的 contains= 參數。這是而且應該是最常見的機製。它安排新類包含現有類的所有結構,特別是指定了相同類的所有槽。生成的類擴展被定義為 simple ,對方法定義具有重要影響(請參閱下麵有關此主題的部分)。

  2. 使class1成為虛擬類的子類,可以通過調用setClassUnion使子類成為新類聯合的成員,或者通過調用setIs將類添加到現有類聯合或作為現有虛擬類的新子類。無論哪種情況,都意味著為類聯合或其他超類定義的方法對於子類都可以正確工作。這可能取決於子類結構中的某些相似性,或者簡單地表明超類方法是根據適用於所有子類的通用函數來定義的。這些關係通常也很簡單。

  3. 供應coercereplace論點setAs.R允許任意繼承關係,使用相同的機製通過調用來定義強製方法setAs。兩者的區別很簡單setAs需要調用as進行轉換,而在調用之後setIs,對象將自動轉換為超類。

    自動特性是危險的部分,主要是因為它會導致子類潛在繼承的方法不起作用。請參閱下麵有關繼承的部分。如果所涉及的兩個類實際上並未繼承大量方法,如下麵的第一個示例所示,那麽危險可能相對較小。

    如果超類繼承了子類僅具有默認或遠程繼承方法的方法,則更有可能出現問題。在這種情況下,一般建議改用setAs 機製,除非有強有力的反駁理由。否則,準備重寫一些繼承的方法。

考慮到這一點,本節的其餘部分說明了將 coerce=replace= 參數提供給 setIs 時會發生的情況。

coercereplace 參數是定義如何將 class1 對象強製為 class2 以及如何替換與 class2 對應的子類對象部分的函數。其中第一個是一個參數的函數,應該是 from ,第二個參數是兩個參數( fromvalue )。有關詳細信息,請參閱下麵有關強製函數的部分。

當指定 by 時,強製過程首先強製到此類,然後強製到 class2 。您不太可能直接使用 by 參數,但它用於定義有關類的緩存信息。

setIs 返回(不可見)的值是 class1 的修訂後的類定義。

強製、替換和測試函數

coerce 參數是將 class1 對象轉換為 class2 對象的函數。 replace 參數是兩個參數的函數,它修改 class1 對象(第一個參數)以替換其對應於 class2 的部分(作為第二個參數 value 提供)。然後它返回修改後的對象作為調用的值。換句話說,它充當實現表達式 as(object, class2) <- value 的替換方法。

考慮 coercereplace 函數的最簡單方法是考慮通常意義上的 class1 包含 class2 的情況,包括第二類的槽。 (重複一遍,在這種情況下,您不會調用 setIs ,但類比顯示了調用時會發生什麽。)

在這種情況下,coerce 函數隻會通過從 class1 對象中提取相應的槽來創建 class2 對象。 replace 函數將替換 class1 對象中與 class2 對應的槽,並返回修改後的對象作為其值。

有關這些函數的更多討論,請參閱 setAs 函數的文檔。 (不幸的是,該函數的參數 def 對應於此處的參數 coerce。)

如果將函數作為 test 參數提供,則繼承關係也可以是有條件的。這應該是一個隻有一個參數的函數,根據提供的對象是否滿足關係 is(object, class2) 返回 TRUEFALSE 。一般來說,不鼓勵類之間的條件關係,因為它們需要針對每個對象進行計算來確定其有效性。它們不能像普通關係那樣有效地應用,並且往往會使使用它們的代碼更難以解釋。注意:條件繼承不用於分派方法。條件超類的方法不會被繼承。相反,應該為子類定義一個方法來測試條件關係。

繼承方法

為特定簽名(與函數的一個或多個形式參數匹配的類)編寫的方法自然會假設與參數相對應的對象可以被視為來自相應的類。這些對象將具有類的所有插槽和可用方法。

選擇和分派方法的代碼可確保此假設是正確的。如果繼承是 “simple”,即通過在調用 setClass 時使用一次或多次 contains= 參數來定義,則通常不需要額外的工作。類是從超類繼承的,具有相同的定義。

當通過對 setIs 的通用調用來定義繼承時,需要額外的計算。這種形式的繼承意味著子類不僅包含超類的槽,而且需要顯式調用強製和/或替換方法。為了確保正確計算,在計算方法體之前,通過調用 as 來補充繼承的方法。

在這種情況下生成的對 as 的調用具有參數 strict = FALSE ,這意味著隻要它具有所有適當的槽,就可以在轉換後的對象中保留額外的信息。 (正是這個選項允許使用簡單的子類對象而無需進行任何更改。)當您編寫強製方法時,您可能希望利用該選項。

通過非簡單擴展繼承的方法可能會導致歧義或意外選擇。如果 class2 是一個隻有幾個適用方法的專用類,則創建繼承關係可能對 class1 的行為影響不大。但如果 class2 是一個有很多方法的類,你可能會發現你現在為 class1 繼承了一些不需要的方法,在某些情況下,無法繼承預期的方法。在下麵的第二個示例中,可能會假設來自類 "factor" 的非簡單繼承通過該類繼承 S3 方法。但 S3 類是不明確的,實際上是 "character" 而不是 "factor"

對於某些泛型函數,由非簡單擴展繼承的方法或者已知為無效,或者很可能無效,因此已定義泛型函數以排除此類繼承。例如initialize方法必須返回目標類的對象;如果擴展很簡單,這很簡單,因為沒有對參數對象進行任何更改,但本質上是不可能的。因此,泛型函數堅持隻對繼承進行簡單的擴展。有關機製,請參閱 setGenericsimpleInheritanceOnly 參數。您可以在定義新的通用函數時使用此機製。

如果您遇到允許非簡單繼承的函數的問題,有兩種基本選擇。或者退出 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-devel大神的英文原創作品 Specify a Superclass Explicitly。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。