メソッドとフィールドの更新
CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 38/57。
メソッドはsetRefClass()のmethodsリストに記述します。メソッド内ではフィールドは通常の名前として扱われ、<<-によってフィールドが変更されます。Coddy runnerでは、メソッドを持つクラスを定義すると、オプションのcodetoolsパッケージについてRが注記を表示するため、定義をsuppressMessages()で囲みます:
Counter <- suppressMessages(setRefClass("Counter",
fields = list(count = "numeric"),
methods = list(
add = function(n = 1) {
count <<- count + n
},
report = function() paste("count is", count)
)
))
c1 <- Counter$new(count = 0)
c1$add()
c1$add(5)
print(c1$report())出力:
[1] "count is 6".self はメソッドが呼び出されたオブジェクトです。invisible(.self) で終わるメソッドはオブジェクトを返すため、呼び出しを連結できます:
Counter <- suppressMessages(setRefClass("Counter",
fields = list(count = "numeric"),
methods = list(
add = function(n = 1) {
count <<- count + n
invisible(.self)
}
)
))
c1 <- Counter$new(count = 0)
c1$add(2)$add(3)$add(4)
print(c1$count)出力:
[1] 9メソッド initialize は $new() 内で実行されます。initFields(...) は渡されたフィールドを設定します。その後、メソッドは残りのフィールドにデフォルト値を設定できます。メソッドは名前で互いを呼び出します。
Account <- suppressMessages(setRefClass("Account",
fields = list(owner = "character", balance = "numeric"),
methods = list(
initialize = function(...) {
initFields(...)
if (length(balance) == 0) balance <<- 0
invisible(.self)
},
deposit = function(x) balance <<- balance + x,
deposit_twice = function(x) {
deposit(x)
deposit(x)
}
)
))
a <- Account$new(owner = "Ada")
a$deposit_twice(10)
print(a$balance)出力:
[1] 20メソッド内では、フィールド名に対する単純な <- は、その名前のローカル変数を作成し、フィールドは変更しません。フィールドを変更する場合は、必ず <<- を使用します。
Counter <- suppressMessages(setRefClass("Counter",
fields = list(count = "numeric"),
methods = list(
broken = function() count <- count + 1,
working = function() count <<- count + 1
)
))
c1 <- Counter$new(count = 0)
c1$broken()
c1$broken()
c1$working()
print(c1$count)出力:
[1] 1チャレンジ
簡単Stack 参照クラスを Stack.R に完成させてください。アイテムはフィールド items(character 型、末尾がトップ)に保持され、4 つのメソッドがあります。
push(x)はxをトップに追加し、invisible(.self)を返すため、push をチェーンできます。pop()はトップのアイテムを削除して返します。スタックが空の場合はnothingを返します。peek()はトップのアイテムを削除せずに返します。空の場合はnothingを返します。size()はアイテム数を返します。
定義はすでに suppressMessages() でラップされています。提供されたコードは push a b、pop、peek のコマンドを読み取り、その後、チェーンした 1 回の呼び出しでさらに 2 つのアイテムを追加し、サイズを出力します。
コードは Stack.R に記述してください。main.R には提供された入出力コードが含まれており、編集できません。
自分で試してみよう
source("Stack.R")
# 提供された入出力コード: そのままにしておく
input <- suppressWarnings(readLines(file("stdin")))
s <- Stack$new()
for (cmd in input) {
if (startsWith(cmd, "push ")) {
items <- strsplit(substring(cmd, 6), " ")[[1]]
for (it in items) s$push(it)
} else if (cmd == "pop") {
cat("popped ", s$pop(), "\n", sep = "")
} else if (cmd == "peek") {
cat("top ", s$peek(), "\n", sep = "")
}
}
s$push("x")$push("y")
cat("size after two chained pushes: ", s$size(), "\n", sep = "")
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rオンラインコンパイラ