NextMethod
位於 methods
包(package)。 說明
對 callNextMethod
的調用隻能出現在方法定義中。然後,它會調用當前方法之後的第一個繼承方法,並將當前方法的參數傳遞給下一個方法。該方法調用的值是 callNextMethod
的值。
用法
callNextMethod(...)
參數
... |
可選地,函數在下一次調用中的參數(但請注意,調度如下麵的詳細說明所示;參數對選擇下一個方法沒有影響。) 如果對 不帶參數調用通常是使用 |
細節
‘next’ 方法(即第一個繼承方法)被定義為如果當前方法不存在則將被調用的方法。這就是 more-or-less 所發生的情況:當前方法(準確地說,是由調用 callNextMethod
的方法的 defined
槽給出的簽名的方法)從當前方法的副本中刪除通用,並且調用 selectMethod
來查找下一個方法(結果緩存在發生調用的方法對象中,因此每個參數類組合的每個會話通常隻進行一次搜索)。
下一個方法是根據當前方法的簽名定義的,而不是根據參數的實際類定義的。特別是,修改任何參數都不會影響選擇。因此,如果調用函數在 callNextMethod()
調用之前分配不同類的對象,則可以使用無效參數調用所選的下一個方法。請小心對此類參數的任何分配。
即使原始方法集是一致的,下一個方法的選擇也可能不明確。請參閱“Ambiguous Selection” 部分。
使用當前參數調用該方法的聲明更準確如下。當前調用中丟失的參數仍然丟失(請記住,"missing"
是方法簽名中的有效類)。對於原始調用中出現的形式參數,例如 x
,在下一個方法調用中會有一個對應的參數,相當於 x = x
。實際上,這意味著下一個方法會看到相同的實際參數,但參數僅計算一次。
值
所選方法返回的值。
模棱兩可的選擇
有兩種相當常見的情況,其中下一個方法的選擇是不明確的,即使原始方法集明確地唯一定義了所有方法選擇。在這些情況下,應該通過調用特定函數或調用具有不同參數的泛型來替換callNextMethod()
。
最有可能出現的情況是二元運算符的方法,通常是通過一組通用函數之一。請參閱下麵的"rnum"
類示例。此類示例通常需要三個方法:兩個用於第一個或第二個參數來自類的情況,第三個用於兩個參數都來自類的情況。如果最後一個方法使用 callNextMethod
,則其他兩個方法同樣有效。這種歧義性與首先需要定義雙參數方法的歧義性完全相同。
事實上,這兩種可能性在概念上和形式上都同樣有效。如下例所示,應用程序的邏輯通常需要顯式選擇計算,或者使用修改後的參數調用通用函數來選擇適當的方法。
歧義的另一個可能來源是直接從多個其他類繼承的類(標準術語中的“mixin”)。如果泛型具有與兩個超類對應的方法,則再次需要當前類的方法來解決歧義。使用callNextMethod
將再次重新產生歧義。同樣,必須在調用方法中做出一些明確的選擇。
這些歧義並不是糟糕設計的結果,但它們確實需要解決方法。其他歧義通常反映繼承樹中的不一致,例如某個類出現在超類中的多個位置。這種情況應該很少見,但是由於多個包中的類獨立定義,所以不能排除這種情況。
例子
## callNextMethod() used for the Math, Math2 group generic functions
## A class to automatically round numeric results to "d" digits
rnum <- setClass("rnum", slots = c(d = "integer"), contains = "numeric")
## Math functions operate on the rounded numbers, return a plain
## vector. The next method will always be the default, usually a primitive.
setMethod("Math", "rnum",
function(x)
callNextMethod(round(as.numeric(x), x@d)))
setMethod("Math2", "rnum",
function(x, digits)
callNextMethod(round(as.numeric(x), x@d), digits))
## Examples of callNextMethod with two arguments in the signature.
## For arithmetic and one rnum with anything, callNextMethod with no arguments
## round the full accuracy result, and return as plain vector
setMethod("Arith", c(e1 ="rnum"),
function(e1, e2)
as.numeric(round(callNextMethod(), e1@d)))
setMethod("Arith", c(e2 ="rnum"),
function(e1, e2)
as.numeric(round(callNextMethod(), e2@d)))
## A method for BOTH arguments from "rnum" would be ambiguous
## for callNextMethod(): the two methods above are equally valid.
## The method chooses the smaller number of digits,
## and then calls the generic function, postponing the method selection
## until it's not ambiguous.
setMethod("Arith", c(e1 ="rnum", e2 = "rnum"),
function(e1, e2) {
if(e1@d <= e2@d)
callGeneric(e1, as.numeric(e2))
else
callGeneric(as.numeric(e1), e2)
})
## For comparisons, callNextMethod with the rounded arguments
setMethod("Compare", c(e1 = "rnum"),
function(e1, e2)
callNextMethod(round(e1, e1@d), round(e2, e1@d)))
setMethod("Compare", c(e2 = "rnum"),
function(e1, e2)
callNextMethod(round(e1, e2@d), round(e2, e2@d)))
## similarly to the Arith case, the method for two "rnum" objects
## can not unambiguously use callNextMethod(). Instead, we rely on
## The rnum() method inhertited from Math2 to return plain vectors.
setMethod("Compare", c(e1 ="rnum", e2 = "rnum"),
function(e1, e2) {
d <- min(e1@d, e2@d)
callGeneric(round(e1, d), round(e2, d))
})
set.seed(867)
x1 <- rnum(10*runif(5), d=1L)
x2 <- rnum(10*runif(5), d=2L)
x1+1
x2*2
x1-x2
## Simple examples to illustrate callNextMethod with and without arguments
B0 <- setClass("B0", slots = c(s0 = "numeric"))
## and a function to illustrate callNextMethod
f <- function(x, text = "default") {
str(x) # print a summary
paste(text, ":", class(x))
}
setGeneric("f")
setMethod("f", "B0", function(x, text = "B0") {
cat("B0 method called with s0 =", x@s0, "\n")
callNextMethod()
})
b0 <- B0(s0 = 1)
## call f() with 2 arguments: callNextMethod passes both to the default method
f(b0, "first test")
## call f() with 1 argument: the default "B0" is not passed by callNextMethod
f(b0)
## Now, a class that extends B0, with no methods for f()
B1 <- setClass("B1", slots = c(s1 = "character"), contains = "B0")
b1 <- B1(s0 = 2, s1 = "Testing B1")
## the two cases work as before, by inheriting the "B0" method
f(b1, b1@s1)
f(b1)
B2 <- setClass("B2", contains = "B1")
## And, a method for "B2" that calls with explicit arguments.
## Note that the method selection in callNextMethod
## uses the class of the *argument* to consistently select the "B0" method
setMethod("f", "B2", function(x, text = "B1 method") {
y <- B1(s0 = -x@s0, s1 ="Modified x")
callNextMethod(y, text)
})
b2 <- B2(s1 = "Testing B2", s0 = 10)
f(b2, b2@s1)
f(b2)
## Be careful: the argument passed must be legal for the method selected
## Although the argument here is numeric, it's still the "B0" method that's called
setMethod("f", "B2", function(x, text = "B1 method") {
callNextMethod(x@s0, text)
})
## Now the call will cause an error:
tryCatch(f(b2), error = function(e) cat(e$message,"\n"))
參考
Chambers, John M. (2016) Extending R, Chapman & Hall. (Chapters 9 and 10.)
也可以看看
callGeneric
使用當前調度規則調用通用函數(通常用於組通用函數); Methods_Details 用於方法分派的一般行為。
相關用法
- R as 強製對象屬於某個類
- R language-class 表示未評估語言對象的類
- R className 類名包含對應的包
- R BasicClasses 基本數據類型對應的類
- R callGeneric 從方法調用當前通用函數
- R findClass 查找類定義
- R setOldClass 注冊舊式 (S3) 類和繼承
- R ReferenceClasses 具有按引用處理的字段的對象(OOP 樣式)
- R MethodsList 方法列表對象
- R setGroupGeneric 創建函數的組通用版本
- R StructureClasses 基本結構對應的類
- R showMethods 顯示指定函數或類的所有方法
- R getMethod 獲取或測試方法的定義
- R slot 正式類對象中的槽
- R S4groupGeneric S4組通用函數
- R methodUtilities 用於方法和 S-Plus 兼容性的實用函數
- R getClass 獲取類定義
- R evalSource 使用源文件中的函數定義,無需重新安裝包
- R is 對象是來自類嗎?
- R isSealedMethod 檢查密封方法或類
- R cbind2 按列或行組合兩個對象
- R GenericFunctions 管理通用函數的工具
- R dotsMethods 在方法簽名中使用...
- R S3Part 包含 S3 類的 S4 類
- R nonStructure-class 基本類型的非結構 S4 類
注:本文由純淨天空篩選整理自R-devel大神的英文原創作品 Call an Inherited Method。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。