验证器与辅助函数
本课属于 Coddy R 学习旅程的“面向对象编程”单元。第 5 课,共 57 课。
构造函数会检查类型;验证器会检查值。按照惯例,validate_money() 接收一个对象,对每条不满足的规则调用 stop() 并给出清晰的消息,一切正常时则返回该对象。call. = FALSE 可以让函数调用不出现在消息中:
new_money <- function(amount = double(), currency = character()) {
stopifnot(is.double(amount), is.character(currency))
structure(list(amount = amount, currency = currency), class = "money")
}
validate_money <- function(x) {
if (x$amount < 0) stop("amount must not be negative", call. = FALSE)
if (nchar(x$currency) != 3) stop("currency must have 3 letters", call. = FALSE)
x
}
m <- validate_money(new_money(-5, "EUR"))输出:
Error: amount must not be negative
Execution halted辅助函数是供其他代码调用的函数。它以类的名称命名,会将输入转换为正确的类型,填入默认值,并将结果传递给构造函数和验证函数:
new_money <- function(amount = double(), currency = character()) {
stopifnot(is.double(amount), is.character(currency))
structure(list(amount = amount, currency = currency), class = "money")
}
validate_money <- function(x) {
if (x$amount < 0) stop("amount must not be negative", call. = FALSE)
x
}
money <- function(amount, currency = "EUR") {
validate_money(new_money(as.double(amount), toupper(currency)))
}
m <- money("12", "usd")
cat(m$amount, m$currency)输出:
12 USD读取用户输入的代码会用 tryCatch() 捕获验证函数的错误,并显示传递给 stop() 的文本 conditionMessage(e):
validate_age <- function(x) {
if (x$years < 0) stop("age must not be negative", call. = FALSE)
if (x$years > 150) stop("age is too large", call. = FALSE)
x
}
age <- function(years) validate_age(structure(list(years = as.double(years)), class = "age"))
for (input in c("30", "-2", "200")) {
result <- tryCatch(paste("ok", age(input)$years), error = function(e) conditionMessage(e))
cat(result, "\n")
}输出:
ok 30
age must not be negative
age is too large 这三个函数各司其职。new_money() 严格而快速,适用于类型已经正确的代码。validate_money() 负责处理值的规则,这些规则可能很慢,也可能很多。money() 用起来更方便,程序的其他部分都会使用它:
new_money() # 只检查类型;用 structure() 构建对象
validate_money() # 检查值是否符合规则;不符合时用 stop() 输出消息,否则返回 x
money() # 转换输入,然后调用 validate_money(new_money(...))挑战
简单new_score(points, max) 在 Score.R 中构建一个 score 对象。请在同一个文件中完成其他函数:
validate_score(x)按顺序检查条件,否则分别以points must not be negative、max must be positive或points must not exceed max终止,并返回x。score(points, max = 100)使用as.double()转换两个参数,并返回validate_score(new_score(...))。format.score(x, ...)返回45/50 (90%),百分比四舍五入为整数。
在每个 stop() 中使用 call. = FALSE。提供的代码会读取 45 50,打印格式化后的分数,或者打印 error: 和错误消息。
请将代码写在 Score.R 中。main.R 包含提供的输入/输出代码,不能编辑。
亲手试试
source("Score.R")
# 提供的输入和输出代码:保持原样。
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, " ")[[1]]
s <- tryCatch(score(p[1], p[2]), error = function(e) conditionMessage(e))
if (is.character(s)) cat("error: ", s, "\n", sep = "") else cat(format(s), "\n", sep = "")
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: R 在线编译器