Menu
CoddyTech

内置类型的方法

本课属于 Coddy R 学习旅程的“面向对象编程”单元。第 28 课,共 57 课。

setMethod() 还会为 length() 和 summary() 等基础函数添加 S4 方法。基础函数对其他所有内容仍然有效,而你的类则有自己的行为:

setClass("Playlist", slots = c(name = "character", songs = "character"))
setMethod("length", "Playlist", function(x) length(x@songs))
pl <- new("Playlist", name = "gym", songs = c("a", "b", "c"))
print(length(pl))
print(length(c(1, 2)))

输出:

[1] 3
[1] 2

运算符也是泛型。针对 + 的方法会在 signature() 中指定两侧的类。两个参数分别称为 e1 和 e2:

setClass("Money", slots = c(amount = "numeric"))
setMethod("show", "Money", function(object) cat(sprintf("%.2f", object@amount), "\n"))
setMethod("+", signature("Money", "Money"), function(e1, e2) {
  new("Money", amount = e1@amount + e2@amount)
})
new("Money", amount = 2.5) + new("Money", amount = 4)

输出:

6.50 

group generic Arith 一次代表 +、-、*、/、^ 等所有运算符。在它的方法内部,callGeneric() 会对你传入的值重复使用相应的运算符:

setClass("Money", slots = c(amount = "numeric"))
setMethod("Arith", signature("Money", "numeric"), function(e1, e2) {
  new("Money", amount = callGeneric(e1@amount, e2))
})
m <- new("Money", amount = 10)
cat((m * 3)@amount, (m / 4)@amount, (m - 1)@amount)

输出:

30 2.5 9

组泛型 Compare 涵盖 ==、<、> 等运算符。它的方法会返回 callGeneric() 对这些槽位进行调用后得到的逻辑值:

setClass("Money", slots = c(amount = "numeric"))
setMethod("Compare", signature("Money", "Money"), function(e1, e2) {
  callGeneric(e1@amount, e2@amount)
})
a <- new("Money", amount = 5)
b <- new("Money", amount = 8)
cat(a < b, a == b, a >= b)

输出:

TRUE FALSE FALSE
challenge icon

挑战

简单

Money.R 中的类 Money 有两个槽:amount(数值型)和 currency(字符型)。添加四个方法:

  • show() 打印 12.50 EUR 和一个换行符;
  • 为两个 Money 对象添加 + 方法,返回它们的和;如果货币不同,则停止并显示 cannot add EUR and USD(使用 call. = FALSE);
  • 为 Money 对象和一个数字添加 * 方法,返回缩放后的金额;
  • 为两个 Money 对象添加 == 方法,当金额和货币都相等时返回 TRUE。

提供的代码会读取 10:EUR + 2.5:EUR、4:USD * 3 或 1:EUR == 1:EUR 这样的行,并打印结果,或打印 error: 和错误消息。

你的代码写在 Money.R 中。main.R 包含提供的输入/输出代码,不能编辑。

亲手试试

source("Money.R")

# 提供的输入和输出代码:保持原样。
input <- suppressWarnings(readLines(file("stdin")))
parse_money <- function(t) {
  p <- strsplit(t, ":")[[1]]
  new("Money", amount = as.numeric(p[1]), currency = p[2])
}
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  a <- parse_money(p[1])
  tryCatch({
    if (p[2] == "+") print(a + parse_money(p[3]))
    if (p[2] == "*") print(a * as.numeric(p[3]))
    if (p[2] == "==") cat(a == parse_money(p[3]), "\n", sep = "")
  }, error = function(e) cat("error: ", conditionMessage(e), "\n", sep = ""))
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: R 在线编译器