使用 inherits() 检查继承关系
本课属于 Coddy R 学习旅程的“面向对象编程”单元。第 15 课,共 57 课。
inherits(x, "employee") 会检查 x 的类向量中是否包含 employee,所以对于经理也会返回 TRUE。与 class(x) == "employee" 比较时,会分别检查每个位置并返回一个向量,而这在 if 中会出错:
m <- structure(list(), class = c("manager", "employee"))
print(inherits(m, "employee"))
print(inherits(m, "intern"))
print(class(m) == "employee")输出:
[1] TRUE
[1] FALSE
[1] FALSE TRUE给定多个名称时,如果对象的类包含其中任意一个,inherits() 就会返回 TRUE。使用 which = TRUE 时,它会返回每个名称在类向量中的位置,不存在的名称则返回 0:
p <- structure(list(), class = c("fragile", "express", "parcel"))
print(inherits(p, c("letter", "parcel")))
print(inherits(p, c("express", "letter", "parcel"), which = TRUE))输出:
[1] TRUE
[1] 2 0 3只适用于某一类类的函数会用 inherits() 检查参数,否则会显示清晰的提示并停止运行:
raise <- function(x, pct) {
if (!inherits(x, "employee")) stop("raise() needs an employee", call. = FALSE)
x$salary <- x$salary * (1 + pct / 100)
x
}
m <- structure(list(salary = 50000), class = c("manager", "employee"))
print(raise(m, 10)$salary)
print(tryCatch(raise(list(salary = 1), 10), error = function(e) conditionMessage(e)))输出:
[1] 55000
[1] "raise() needs an employee"使用 inherits() 的 Filter() 会从混合列表中筛选出属于某个类族的成员,包括所有子类:
staff <- list(
structure(list(name = "Ada"), class = c("manager", "employee")),
structure(list(name = "Bo"), class = "employee"),
structure(list(name = "Cy"), class = c("intern", "employee")),
structure(list(name = "Dee"), class = c("director", "manager", "employee"))
)
managers <- Filter(function(x) inherits(x, "manager"), staff)
print(vapply(managers, function(x) x$name, character(1)))输出:
[1] "Ada" "Dee"挑战
简单目录中存放着图书、电子书和 DVD。构造函数定义在 Item.R、Book.R、Ebook.R 和 Dvd.R 中;电子书的类是 c("ebook", "book", "item")。在 Catalogue.R 中使用 inherits() 完成两个函数:
count_of(items, kind)返回类向量中任意位置包含kind的项目数量。titles_of(items, kind)按顺序返回这些项目的标题。
提供的代码会读取 book Dune、ebook Emma、dvd Alien 这些行,并查询 ? book,然后打印 book: 2 (Dune, Emma);如果没有匹配项,则只打印 dvd: 0。
你的代码应写在 Item.R、Book.R、Ebook.R、Dvd.R 和 Catalogue.R 中。main.R 包含提供的输入/输出代码,不能编辑。
亲手试试
source("Item.R")
source("Book.R")
source("Ebook.R")
source("Dvd.R")
source("Catalogue.R")
# 提供的输入和输出代码:保持原样。
input <- suppressWarnings(readLines(file("stdin")))
items <- list()
for (line in input) {
p <- strsplit(line, " ")[[1]]
rest <- paste(p[-1], collapse = " ")
if (p[1] == "?") {
titles <- titles_of(items, p[2])
shown <- if (length(titles) > 0) paste0(" (", paste(titles, collapse = ", "), ")") else ""
cat(p[2], ": ", count_of(items, p[2]), shown, "\n", sep = "")
} else {
items[[length(items) + 1]] <- switch(p[1], book = new_book(rest), ebook = new_ebook(rest), dvd = new_dvd(rest))
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: R 在线编译器