Menu
CoddyTech

使用 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"
challenge icon

挑战

简单

目录中存放着图书、电子书和 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))
  }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: R 在线编译器