Menu
Coddy logo textTech

inherits()で確認する

CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 15/57。

inherits(x, "employee") は employee が x のクラスベクトル内のどこかに存在するかどうかを尋ねるため、マネージャーに対しても TRUE になります。class(x) == "employee" との比較では各位置を個別に確認し、ベクトルが返されるため、if 内では失敗します。

m <- structure(list(), class = c("manager", "employee"))
print(inherits(m, "employee"))
print(inherits(m, "intern"))
print(class(m) == "employee")

出力:

[1] TRUE
[1] FALSE
[1] FALSE  TRUE

複数の名前を指定すると、オブジェクトがそのいずれかを持っている場合、inherits() は TRUE になります。which = TRUE を指定すると、各名前についてクラスベクトル内の位置を返します。名前が存在しない場合は 0 を返します:

p <- structure(list(), class = c("fragile", "express", "parcel"))
print(inherits(p, c("letter", "parcel")))
print(inherits(p, c("express", "letter", "parcel"), which = TRUE))

出力:

[1] TRUE
[1] 2 0 3

1つのクラス族に対してのみ意味を持つ関数は、inherits() を使って引数をチェックし、それ以外の場合は明確なメッセージを表示して停止します。

raise <- function(x, pct) {
  if (!inherits(x, "employee")) stop("raise() needs an employee", call. = FALSE)
  x$salary <- x$salary * (1 + pct / 100)
  x
}
m <- structure(list(salary = 50000), class = c("manager", "employee"))
print(raise(m, 10)$salary)
print(tryCatch(raise(list(salary = 1), 10), error = function(e) conditionMessage(e)))

出力:

[1] 55000
[1] "raise() needs an employee"

Filter()とinherits()を使うと、混在したリストから、すべてのサブクラスを含む1つのファミリーのメンバーを選び出せます。

staff <- list(
  structure(list(name = "Ada"), class = c("manager", "employee")),
  structure(list(name = "Bo"), class = "employee"),
  structure(list(name = "Cy"), class = c("intern", "employee")),
  structure(list(name = "Dee"), class = c("director", "manager", "employee"))
)
managers <- Filter(function(x) inherits(x, "manager"), staff)
print(vapply(managers, function(x) x$name, character(1)))

出力:

[1] "Ada" "Dee"
challenge icon

チャレンジ

簡単

カタログには本、電子書籍、DVDが収録されています。コンストラクタは Item.R、Book.R、Ebook.R、Dvd.R に定義されています。電子書籍のクラスは c("ebook", "book", "item") です。Catalogue.R で、inherits() を使って2つの関数を完成させてください。

  • count_of(items, kind) は、クラスベクトル内のどこかに kind を持つアイテムの数を返します。
  • titles_of(items, kind) は、それらのアイテムのタイトルを順番どおりに返します。

提供されたコードは、book Dune、ebook Emma、dvd Alien の行を読み込み、? book のようなクエリを受け付け、book: 2 (Dune, Emma) を出力します。一致するものがない場合は、dvd: 0 のみを出力します。

コードは Item.R、Book.R、Ebook.R、Dvd.R、Catalogue.R に記述します。main.R には提供された入出力コードが含まれており、編集できません。

自分で試してみよう

source("Item.R")
source("Book.R")
source("Ebook.R")
source("Dvd.R")
source("Catalogue.R")

# 提供された入出力コード: そのままにしておく
input <- suppressWarnings(readLines(file("stdin")))
items <- list()
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  rest <- paste(p[-1], collapse = " ")
  if (p[1] == "?") {
    titles <- titles_of(items, p[2])
    shown <- if (length(titles) > 0) paste0(" (", paste(titles, collapse = ", "), ")") else ""
    cat(p[2], ": ", count_of(items, p[2]), shown, "\n", sep = "")
  } else {
    items[[length(items) + 1]] <- switch(p[1], book = new_book(rest), ebook = new_ebook(rest), dvd = new_dvd(rest))
  }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Rオンラインコンパイラ