Menu
CoddyTech

インデックス付けと追加

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

obj[key]はメソッド[]を呼び出し、obj[key] = valueは[]=を呼び出します。これらを定義すると、クラスに配列やハッシュの角括弧構文を与え、その意味はクラスに合ったものにできます。

class Inventory
  def initialize
    @stock = Hash.new(0)
  end

  def [](name)
    @stock[name]
  end

  def []=(name, qty)
    @stock[name] = qty
  end
end

inv = Inventory.new
inv["apple"] = 5
inv["apple"] += 2
puts inv["apple"]
puts inv["pear"]

出力:

7
0

[]はいくつかの引数(たとえば行と列)を受け取り、それらをチェックできます。存在しない位置に対する通常のエラーはIndexErrorです。

class Board
  def initialize(size)
    @size = size
    @cells = Array.new(size) { Array.new(size, ".") }
  end

  def [](row, col)
    check(row, col)
    @cells[row][col]
  end

  def []=(row, col, mark)
    check(row, col)
    @cells[row][col] = mark
  end

  def check(row, col)
    raise IndexError, "no cell #{row},#{col}" unless row.between?(0, @size - 1) && col.between?(0, @size - 1)
  end
end

b = Board.new(3)
b[1, 1] = "X"
puts b[1, 1] + b[0, 0]
begin
  b[3, 0]
rescue IndexError => e
  puts e.message
end

出力:

X.
no cell 3,0

<<は追加演算子です。これからselfを返すと、配列でのlist << a << bのように連鎖させることができます。

class Shelf
  def initialize
    @books = []
  end

  def <<(title)
    @books << title
    self
  end

  def to_s
    @books.join(" | ")
  end
end

shelf = Shelf.new
shelf << "Dune" << "Emma" << "Ulysses"
puts shelf

出力:

Dune | Emma | Ulysses

[]=による代入は、他のセッターと同様に、メソッドの戻り値ではなく代入された値を返します。角括弧と<<によって、クラスに小さくてなじみのあるインターフェースを与えられます。

inv["apple"] = 5          # []=("apple", 5) を呼び出し、式の値は 5 になる
inv["apple"]              # []("apple") を呼び出す
shelf << "Dune" << "Emma"  # << は self を返すため、連鎖して呼び出せる
board[1, 2] = "X"         # []=(1, 2, "X")
challenge icon

チャレンジ

簡単

Inventory クラスを完成させてください。inv[name] はアイテムの数量(不明な場合は 0)を返し、inv[name] = qty はその数量を設定します。また、inv << name はそのアイテムを 1 つ追加し、呼び出しを連結できるように在庫を返します。to_s は名前のアルファベット順で apple: 3, pear: 1 を返し、数量が 0 のアイテムは除外します。アイテムがない場合は empty を返します。

提供されたコードはコマンドを読み取ります。set apple 5、add apple pear pear(各名前に対して << を連結して呼び出します)、get apple、print の各コマンドを読み取り、get と print の結果を出力します。

コードは inventory.rb に記述してください。main.rb には提供された入出力コードがあり、編集できません。

自分で試してみよう

require_relative 'inventory'

# 提供された入出力コード: そのままにしておく
input = []
while (line = gets)
  input << line.chomp
end
inv = Inventory.new
input.each do |line|
  cmd, *args = line.split
  case cmd
  when "set" then inv[args[0]] = args[1].to_i
  when "add" then args.reduce(inv) { |target, name| target << name }
  when "get" then puts inv[args[0]]
  else puts inv
  end
end
quiz icon腕試し

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

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

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