ジェネリックとUseMethod
CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 7/57。
ジェネリックは、本体がUseMethod("name")である関数です。呼び出されると、最初の引数のクラスを調べ、メソッドname.classを呼び出します。print()とformat()はこのように動作します。独自のジェネリックも作成できます。
speak <- function(x) UseMethod("speak")
speak.dog <- function(x) paste(x$name, "says woof")
speak.cat <- function(x) paste(x$name, "says meow")
rex <- structure(list(name = "Rex"), class = "dog")
tom <- structure(list(name = "Tom"), class = "cat")
print(speak(rex))
print(speak(tom))出力:
[1] "Rex says woof"
[1] "Tom says meow"呼び出し側は1つの呼び出しを書き、各オブジェクトはそれぞれ独自の方法で応答します。これがポリモーフィズムです。混在したリストをループするコードでは、クラスごとにifを書く必要はありません。
speak <- function(x) UseMethod("speak")
speak.dog <- function(x) paste(x$name, "says woof")
speak.cat <- function(x) paste(x$name, "says meow")
pets <- list(structure(list(name = "Rex"), class = "dog"),
structure(list(name = "Tom"), class = "cat"),
structure(list(name = "Bo"), class = "dog"))
for (p in pets) cat(speak(p), "\n")出力:
Rex says woof
Tom says meow
Bo says woof メソッドはジェネリックの引数を受け取ります。円の digits のように、メソッドが独自の追加引数を受け取れるように、ジェネリックに ... パラメーターを指定します。
area <- function(shape, ...) UseMethod("area")
area.square <- function(shape, ...) shape$side^2
area.circle <- function(shape, digits = 2, ...) round(pi * shape$r^2, digits)
sq <- structure(list(side = 3), class = "square")
ci <- structure(list(r = 1), class = "circle")
print(area(sq))
print(area(ci))
print(area(ci, digits = 4))出力:
[1] 9
[1] 3.14
[1] 3.1416UseMethod()は呼び出しをメソッドに渡し、戻ってきません。メソッドが返す値がジェネリック関数の結果となり、UseMethod()の後のコードは実行されません。したがって、ジェネリック関数は1行です。
size <- function(x) {
UseMethod("size")
cat("this line never runs\n")
}
size.box <- function(x) x$w * x$h
b <- structure(list(w = 2, h = 5), class = "box")
print(size(b))出力:
[1] 10チャレンジ
簡単図形は3つのファイルに分かれています。Shape.Rの汎用関数area()を完成させ、次にCircle.Rにメソッドarea.circle()(半径の2乗に円周率を掛けた値)を、Rectangle.Rにメソッドarea.rectangle()(幅に高さを掛けた値)を追加してください。コンストラクターは用意されています。
用意されたコードはcircle 2またはrectangle 3 4の行を読み取り、各図形のクラスと面積を小数点以下2桁で出力します: circle: 12.57。
コードはShape.R、Circle.R、Rectangle.Rに記述してください。main.Rには用意された入出力コードが含まれており、編集できません。
自分で試してみよう
source("Shape.R")
source("Circle.R")
source("Rectangle.R")
# 提供された入出力コード: そのままにしてください
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, " ")[[1]]
s <- if (p[1] == "circle") new_circle(as.numeric(p[2])) else new_rectangle(as.numeric(p[2]), as.numeric(p[3]))
cat(sprintf("%s: %.2f", class(s), area(s)), "\n", sep = "")
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rオンラインコンパイラ