方法查找顺序
本课属于 Coddy R 学习旅程的“面向对象编程”单元。第 13 课,共 57 课。
每次调用时,R 都会从左到右遍历类向量,并运行找到的第一个方法。如果没有任何类包含方法,就会使用默认方法。同一继承层级中的不同对象可能会在不同层级停止:
move <- function(x) UseMethod("move")
move.animal <- function(x) "walks"
move.bird <- function(x) "flies"
move.default <- function(x) "stays"
penguin <- structure(list(), class = c("penguin", "bird", "animal"))
dog <- structure(list(), class = c("dog", "animal"))
rock <- structure(list(), class = "rock")
cat(move(penguin), move(dog), move(rock))输出:
flies walks stays子类通过定义自己的方法来重写父类的方法。重写只会影响子类及其下级类;父类和其他子类仍使用父类的方法:
move <- function(x) UseMethod("move")
move.animal <- function(x) "walks"
move.bird <- function(x) "flies"
move.penguin <- function(x) "swims"
penguin <- structure(list(), class = c("penguin", "bird", "animal"))
sparrow <- structure(list(), class = c("bird", "animal"))
cat(move(penguin), move(sparrow))输出:
swims flies每个泛型都会单独查找。一个对象可以从自己的类中获取 sound(),从父类中获取 move(),而父类方法也可以调用其他泛型,这些泛型会再次根据子类进行分派:
sound <- function(x) UseMethod("sound")
move <- function(x) UseMethod("move")
describe <- function(x) UseMethod("describe")
sound.animal <- function(x) "..."
sound.dog <- function(x) "woof"
move.animal <- function(x) "walks"
describe.animal <- function(x) paste(x$name, "says", sound(x), "and", move(x))
rex <- structure(list(name = "Rex"), class = c("dog", "animal"))
print(describe(rex))输出:
[1] "Rex says woof and walks"对于带有类属性的对象,分派只会查看该属性,然后查看默认方法。该对象内部仍然是一个列表,但不会尝试调用 list 的方法:
size <- function(x) UseMethod("size")
size.list <- function(x) "a list"
size.default <- function(x) "default"
bag <- structure(list(1, 2), class = "bag")
cat(size(list(1, 2)), "/", size(bag))输出:
a list / default挑战
简单正方形是各边相等的矩形。在 Rectangle.R 中编写方法 area.rectangle()、perimeter.rectangle() 和 name.rectangle(),其中 name.rectangle() 返回 rectangle 2x3。在 Square.R 中完成 new_square(side),让它调用 new_rectangle(),并使用类 square;然后只重写 name(),使用 name.square(),使其返回 square 2。正方形必须使用矩形的 area() 和 perimeter()。
泛型函数和 new_rectangle() 已提供。给定代码会读取包含两个数字(矩形)或一个数字(正方形)的行,并打印 square 2: area 4, perimeter 8。
你的代码写在 Rectangle.R 和 Square.R 中。main.R 包含给定的输入/输出代码,不能编辑。
亲手试试
source("Rectangle.R")
source("Square.R")
# 提供的输入/输出代码:保持原样
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
n <- as.numeric(strsplit(line, " ")[[1]])
s <- if (length(n) == 1) new_square(n[1]) else new_rectangle(n[1], n[2])
cat(name(s), ": area ", area(s), ", perimeter ", perimeter(s), "\n", sep = "")
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: R 在线编译器