アクセサ関数
CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 19/57。
カプセル化とは、他のコードがオブジェクトのフィールドに直接アクセスするのではなく、関数を介して操作することです。getterは値を読み取り、setterは値を変更します。S3リストの場合、setterは変更後のコピーを返します。
new_member <- function(name) structure(list(name = name), class = "member")
get_name <- function(p) p$name
set_name <- function(p, value) {
p$name <- value
p
}
p <- new_member("ada")
p <- set_name(p, "Ada Lovelace")
print(get_name(p))出力:
[1] "Ada Lovelace"アクセサーを使うと、それを利用するコードを壊さずに、オブジェクトがデータを格納する方法を変更できます。この温度計は摂氏で値を格納し、求められたときにゲッターが華氏を計算するため、呼び出し元からはフィールド自体が見えません。
new_thermo <- function(c) structure(list(c = c), class = "thermo")
celsius <- function(t) t$c
fahrenheit <- function(t) t$c * 9 / 5 + 32
t <- new_thermo(25)
cat(celsius(t), fahrenheit(t))出力:
25 77R 独自のセッター(names(x) <- ... など)は、置換関数です。x と value をパラメーターとして持つ "name<-" という名前の関数を定義すると、呼び出し側は name(p) <- "Bo" と書けます。R はその関数を呼び出し、結果を p に再代入します。
new_member <- function(name) structure(list(name = name), class = "member")
name <- function(p) p$name
"name<-" <- function(x, value) {
x$name <- trimws(value)
x
}
p <- new_member("ada")
name(p) <- " Bo "
print(name(p))出力:
[1] "Bo"クロージャオブジェクトのゲッターは、プライベートデータのコピーを返します。そのコピーを変更してもオブジェクトは変わらないため、オブジェクトにアクセスする唯一の方法は、オブジェクト自身の関数を介することです:
make_list <- function() {
items <- character(0)
list(add = function(x) items <<- c(items, x),
get_items = function() items)
}
todo <- make_list()
todo$add("milk")
mine <- todo$get_items()
mine[1] <- "HACKED"
print(todo$get_items())出力:
[1] "milk"チャレンジ
簡単連絡先は、name フィールドと email フィールドを持つクラス contact の S3 リストです。Contact.R を完成させてください。
new_contact(name, email)は、メールアドレスを前後の空白を除去し、小文字に変換して保存します。- ゲッター
contact_name(x)とcontact_email(x)。 - 置換関数
"contact_email<-"は、新しいメールアドレスを前後の空白を除去し、小文字に変換して保存するため、呼び出し側ではcontact_email(c1) <- valueと記述できます。
用意されたコードは name,email を読み取り、続いて新しいメールアドレスを読み取り、変更のたびに Ada <ada@x.com> を出力し、最後に保存されているフィールド名を出力します。
コードは Contact.R に記述してください。main.R には用意された入出力コードが含まれており、編集できません。
自分で試してみよう
source("Contact.R")
# 提供された入出力コード: そのままにしておく
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], ",")[[1]]
c1 <- new_contact(p[1], p[2])
cat(contact_name(c1), " <", contact_email(c1), ">\n", sep = "")
for (value in input[-1]) {
contact_email(c1) <- value
cat(contact_name(c1), " <", contact_email(c1), ">\n", sep = "")
}
cat("stored fields: ", paste(names(unclass(c1)), collapse = ", "), "\n", sep = "")
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rオンラインコンパイラ