NextMethod 基础
本课属于 Coddy R 学习旅程的“面向对象编程”单元。第 10 课,共 57 课。
在方法内部,NextMethod() 会使用相同的参数,调用同一个泛型对应的下一个方法。对于只有一个类的对象,下一个方法是默认方法,因此某个方法可以复用通用答案并在此基础上补充内容:
describe <- function(x) UseMethod("describe")
describe.default <- function(x) paste("an object with", length(x), "fields")
describe.task <- function(x) paste0(NextMethod(), ", titled ", x$title)
t <- structure(list(title = "Buy milk", done = FALSE), class = "task")
print(describe(t))输出:
[1] "an object with 2 fields, titled Buy milk"一个对象在向量中可以有多个类,例如 c("urgent", "task")。分派会按顺序尝试这些类,而第一个方法中的 NextMethod() 会转到下一个类对应的方法:
describe <- function(x) UseMethod("describe")
describe.task <- function(x) paste("task:", x$title)
describe.urgent <- function(x) paste("URGENT", NextMethod())
fix <- structure(list(title = "Fix the leak"), class = c("urgent", "task"))
print(describe(fix))输出:
[1] "URGENT task: Fix the leak"NextMethod() 会传递方法接收到的每个参数,包括 sep 这样的额外参数。下一个方法会看到相同的值,你不必再次列出它们:
label <- function(x, sep = ": ") UseMethod("label")
label.default <- function(x, sep = ": ") paste0("item", sep, x$name)
label.box <- function(x, sep = ": ") paste0("[", NextMethod(), "]")
b <- structure(list(name = "tools"), class = "box")
print(label(b))
print(label(b, sep = " = "))输出:
[1] "[item: tools]"
[1] "[item = tools]"Base R 使用 NextMethod(),在对向量取子集时保留其类。默认的 [ 会丢弃类,因此可以使用 "[.percent" 方法执行操作并恢复类:
format.percent <- function(x, ...) paste0(unclass(x) * 100, "%")
"[.percent" <- function(x, i) structure(NextMethod(), class = "percent")
p <- structure(c(0.1, 0.25, 0.5), class = "percent")
print(format(p[2:3]))输出:
[1] "25%" "50%"挑战
简单任务和紧急任务是定义在两个文件中的两个类。在 Task.R 中补全泛型函数 describe()、返回 an item 的默认方法,以及 describe.task()。后者通过调用 NextMethod() 并添加标题,返回 an item: Buy milk。在 Urgent.R 中补全 describe.urgent(),它通过调用 NextMethod() 返回 URGENT an item: Fix bug。
构造函数已提供:紧急任务的类是 c("urgent", "task")。提供的代码会读取 task Buy milk、urgent Fix bug 或其他带标题的单词,将其转换为该类的对象,并为每个对象打印 describe() 的结果。
你的代码写在 Task.R 和 Urgent.R 中。main.R 中是提供的输入/输出代码,不能编辑。
亲手试试
source("Task.R")
source("Urgent.R")
# 提供的输入/输出代码:保持原样。
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
kind <- sub(" .*", "", line)
title <- sub("^[a-z]+ ", "", line)
t <- if (kind == "urgent") new_urgent(title) else if (kind == "task") new_task(title) else structure(list(title = title), class = kind)
cat(describe(t), "\n", sep = "")
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: R 在线编译器