NextMethodの基礎
CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 10/57。
メソッド内では、NextMethod() が同じジェネリックに対する次のメソッドを、同じ引数で呼び出します。1つのクラスを持つオブジェクトの場合、次のメソッドはデフォルトのものなので、メソッドは一般的な結果を再利用して、それに追加できます:
describe <- function(x) UseMethod("describe")
describe.default <- function(x) paste("an object with", length(x), "fields")
describe.task <- function(x) paste0(NextMethod(), ", titled ", x$title)
t <- structure(list(title = "Buy milk", done = FALSE), class = "task")
print(describe(t))出力:
[1] "an object with 2 fields, titled Buy milk"オブジェクトは、c("urgent", "task")のように、ベクトル内に複数のクラスを持つことができます。ディスパッチはそれらを順番に試し、最初のメソッド内のNextMethod()によって、次のクラスに対応するメソッドへ進みます。
describe <- function(x) UseMethod("describe")
describe.task <- function(x) paste("task:", x$title)
describe.urgent <- function(x) paste("URGENT", NextMethod())
fix <- structure(list(title = "Fix the leak"), class = c("urgent", "task"))
print(describe(fix))出力:
[1] "URGENT task: Fix the leak"NextMethod()は、メソッドが受け取ったすべての引数を、sepのような追加の引数も含めて引き継ぎます。次のメソッドは、引数を再度列挙しなくても同じ値を参照できます。
label <- function(x, sep = ": ") UseMethod("label")
label.default <- function(x, sep = ": ") paste0("item", sep, x$name)
label.box <- function(x, sep = ": ") paste0("[", NextMethod(), "]")
b <- structure(list(name = "tools"), class = "box")
print(label(b))
print(label(b, sep = " = "))出力:
[1] "[item: tools]"
[1] "[item = tools]"Base R では、ベクトルのサブセット化時にクラスを維持するために NextMethod() を使用します。デフォルトの [ はクラスを削除するため、"[.percent" メソッドによって処理を実行し、クラスを元に戻します。
format.percent <- function(x, ...) paste0(unclass(x) * 100, "%")
"[.percent" <- function(x, i) structure(NextMethod(), class = "percent")
p <- structure(c(0.1, 0.25, 0.5), class = "percent")
print(format(p[2:3]))出力:
[1] "25%" "50%"チャレンジ
簡単タスクと緊急タスクは、2つのファイルに分かれた2つのクラスです。Task.R では、an item を返す汎用的な describe() とデフォルトメソッド、および NextMethod() を呼び出してタイトルを追加することで an item: Buy milk を返す describe.task() を完成させてください。Urgent.R では、NextMethod() を呼び出して URGENT an item: Fix bug を返す describe.urgent() を完成させてください。
コンストラクターは与えられています。緊急タスクのクラスは c("urgent", "task") です。提供されたコードは、task Buy milk、urgent Fix bug、またはタイトルを伴うその他の単語の行を読み取り、それぞれをそのクラスのオブジェクトにして、各オブジェクトに対して describe() を出力します。
コードは Task.R と Urgent.R に記述します。main.R には提供された入力/出力コードが含まれており、編集できません。
自分で試してみよう
source("Task.R")
source("Urgent.R")
# 提供された入出力コード: そのままにしておく
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
kind <- sub(" .*", "", line)
title <- sub("^[a-z]+ ", "", line)
t <- if (kind == "urgent") new_urgent(title) else if (kind == "task") new_task(title) else structure(list(title = title), class = kind)
cat(describe(t), "\n", sep = "")
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rオンラインコンパイラ