バリデーターとヘルパー
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 3つの関数には、それぞれ1つの役割があります。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オンラインコンパイラ