创建泛型
本课属于 Coddy R 学习旅程的“面向对象编程”单元。第 27 课,共 57 课。
S4 泛型通过 setGeneric() 创建。它的函数体是 standardGeneric("name"),相当于 S4 中的 UseMethod()。调用 setGeneric() 会返回泛型的名称,在顶层调用时会打印该名称:
setGeneric("area", function(shape) standardGeneric("area"))输出:
[1] "area"将调用包装在 invisible() 中,这样这一行就不会出现在输出中。接着,setMethod("area", "Circle", ...) 会为一个类添加方法:
setClass("Circle", slots = c(r = "numeric"))
setClass("Square", slots = c(side = "numeric"))
invisible(setGeneric("area", function(shape) standardGeneric("area")))
setMethod("area", "Circle", function(shape) pi * shape@r^2)
setMethod("area", "Square", function(shape) shape@side^2)
cat(area(new("Circle", r = 1)), area(new("Square", side = 3)))输出:
3.141593 9方法的参数与其泛型相同。泛型有 ... 时,方法可以在它们后面添加自己的命名参数:
setClass("Circle", slots = c(r = "numeric"))
invisible(setGeneric("describe", function(x, ...) standardGeneric("describe")))
setMethod("describe", "Circle", function(x, ..., digits = 2) {
paste("circle of area", round(pi * x@r^2, digits))
})
c1 <- new("Circle", r = 2)
print(describe(c1))
print(describe(c1, digits = 4))输出:
[1] "circle of area 12.57"
[1] "circle of area 12.5664"setMethod() 需要泛型已经存在,因此先加载包含 setGeneric() 的文件。对没有方法的类进行调用时,会报错并指出签名:
invisible(setGeneric("area", function(shape) standardGeneric("area")))
setClass("Circle", slots = c(r = "numeric"))
setMethod("area", "Circle", function(shape) pi * shape@r^2)
area(42)输出:
Error: unable to find an inherited method for function ‘area’ for signature ‘shape = "numeric"’
Execution halted挑战
简单图形是分布在三个文件中的 S4 类。在 Shape.R 中,用 setGeneric() 创建泛型 area(shape) 和 perimeter(shape),并用 invisible() 包装。在 Circle.R 和 Square.R 中声明类,并为每个类添加 area 和 perimeter 方法,使用 setMethod()。
提供的代码会读取 circle 2 或 square 3 这样的行,并打印 circle: area 12.57, perimeter 12.57。
你的代码写在 Shape.R、Circle.R 和 Square.R 中。main.R 包含提供的输入/输出代码,不能编辑。
亲手试试
source("Shape.R")
source("Circle.R")
source("Square.R")
# 已提供的输入/输出代码:保持原样
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, " ")[[1]]
s <- if (p[1] == "circle") new("Circle", r = as.numeric(p[2])) else new("Square", side = as.numeric(p[2]))
cat(sprintf("%s: area %.2f, perimeter %.2f", p[1], area(s), perimeter(s)), "\n", sep = "")
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: R 在线编译器