为现有类定义泛型函数
在前面的小节中,我们掌握了如何运用 R 中已有的类和方法处理模型对象。在 S3 系
统中,允许自行创建类和泛型函数。
前面的例子中,我们使用条件表达式模拟了 head( )的方法分派。虽然模拟成功了,但
一般不建议这样做。S3 泛型函数非常灵活,而且很容易拓展。在定义泛型函数时,我们通常
创建一个函数去调用 UseMethod( )触发方法分派。然后,对泛型函数想要作用的类创建带
有 method.class 形式的方法函数,同时还要创建带有 method.default 形式的默认方法
来应对所有其他情况。这里使用泛型函数和方法重写刚刚那个例子。我们创建一个新的泛型函
数 generic_head( ),它有两个参数:输入对象 x 和需要提取的记录条数 n。泛型函数仅
仅调用 UseMethod("generic_head")来让 R 根据输入对象 x 的类执行方法分派:
generic_head <- function(x, n)
UseMethod("generic_head")
对于原子向量(数值向量、字符向量、逻辑向量等),提取前 n 个元素。因此,我们分
别定义 generic_head.numeric、generic_head.character 等,此外,最好定义
一个默认方法来捕获不能匹配已定义的 generic_head.class 方法的其他所有情况:
generic_head.default <- function(x, n) {
x[1:n]
}
现在的 generic_head 只有一种方法,等价于没有使用泛型函数:
generic_ _head(num_vec, 3)
## [1] 1 2 3
由于我们还没有定义针对data.frame 类的方法,所以提供一个数据框时,函数会自动转
向generic_head.default,又因为要提取的数量超过数据框的列数,导致无效访问而报错:
generic_ _head(data_frame, 3)
## Error in `[.data.frame`(x, 1:n): undefined columns selected
如果我们对 data.frame 定义了方法:
generic_head.data.frame <- function(x, n) {
x[1:n,]
}
那么,就像预期的那样,泛型函数正常运行:
generic_ _head(data_frame, 3)
## x y
## 1 1 0.8867848
## 2 2 0.1169713
## 3 3 0.3186301
你可能注意到了,因为没有进行参数检查,所以之前执行的方法并不稳健。例如,如
果 n 大于输入对象的元素数量,函数就会以非预期的不同方式进行处理。这里就留给你作
为练习,尝试去优化函数,使得方法更稳健,而且能够合适地处理极端情况。