索引与追加
本课属于 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")挑战
简单完成 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
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Ruby 在线编译器