Menu
Coddy logo textTech

メソッドとフィールドの更新

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
challenge icon

チャレンジ

簡単

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 = "")
quiz icon腕試し

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

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

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