オブジェクトとしてのクロージャ
CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 17/57。
Logic & Flowではクロージャについて学びました。関数の中で作られた関数は、その周囲にある変数を保持します。このような関数のリストを返す関数ファクトリは、オブジェクトを作ります。そのローカル変数がオブジェクトのデータであり、関数はそのメソッドです。
make_account <- function(balance = 0) {
deposit <- function(x) balance <<- balance + x
get_balance <- function() balance
list(deposit = deposit, get_balance = get_balance)
}
acc <- make_account(100)
acc$deposit(50)
print(acc$get_balance())出力:
[1] 150ファクトリを呼び出すたびに本体が再実行されるため、それぞれのオブジェクトは独自の変数を持ちます。一方のアカウントを変更しても、もう一方には影響しません。
make_account <- function(balance = 0) {
list(deposit = function(x) balance <<- balance + x,
get_balance = function() balance)
}
ada <- make_account(100)
bo <- make_account(5)
ada$deposit(1)
cat(ada$get_balance(), bo$get_balance())出力:
101 5データは非公開です。balanceはリストの要素ではないため、acc$balanceはNULLであり、そこに代入しても無関係な要素が追加されるだけです。リスト内の関数が、そのオブジェクトの公開インターフェース全体です。
make_account <- function(balance = 0) {
list(get_balance = function() balance)
}
acc <- make_account(100)
print(acc$balance)
acc$balance <- 1e6
print(acc$get_balance())出力:
NULL
[1] 100メソッドは、リストが作られる前にローカル関数として定義されていれば、互いに呼び出すことができます。ここではadd_many()がadd()を再利用します。
make_tally <- function() {
total <- 0
add <- function(x) total <<- total + x
add_many <- function(xs) for (x in xs) add(x)
get <- function() total
list(add = add, add_many = add_many, get = get)
}
t <- make_tally()
t$add(1)
t$add_many(c(2, 3, 4))
print(t$get())出力:
[1] 10チャレンジ
簡単Counter.Rのファクトリ関数make_counter(start = 0)を完成させてください。現在の値を非公開に保ち、4つの関数を含むリストを返します。increment()とdecrement()は値を1増減させ、reset()は値をstartに戻し、value()は現在の値を返します。
提供されたコードは開始値を読み取り、続いて+、-またはresetのコマンドを読み取り、それぞれの後に値を出力します。最後に、返されたリスト内の名前を出力します。このリストには4つの関数だけが含まれていなければなりません。
コードはCounter.Rに記述してください。main.Rには提供された入出力コードが含まれており、編集できません。
自分で試してみよう
source("Counter.R")
# 提供された入出力コード:そのままにしてください
input <- suppressWarnings(readLines(file("stdin")))
counter <- make_counter(as.numeric(input[1]))
for (cmd in input[-1]) {
if (cmd == "+") counter$increment()
if (cmd == "-") counter$decrement()
if (cmd == "reset") counter$reset()
cat(cmd, " -> ", counter$value(), "\n", sep = "")
}
cat("fields visible: ", paste(sort(names(counter)), collapse = ", "), "\n", sep = "")
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rオンラインコンパイラ