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 在线编译器