Menu
CoddyTech

Индексация и добавление

Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 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 добавляет одну единицу этого товара и возвращает инвентарь, чтобы вызовы можно было объединять в цепочку. 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