Menu
CoddyTech

Bộ sưu tập tùy chỉnh

Thuộc phần Lập trình hướng đối tượng trong hành trình Ruby của Coddy. Bài học 40 trên 57.

Một lớp tập hợp kết hợp một số phương thức đặc biệt: each với Enumerable, << để thêm phần tử, size, và to_s cùng inspect để in ra. each cũng nên hoạt động khi không có khối lệnh, bằng cách trả về một bộ liệt kê với to_enum, giống như mảng:

class TodoList
  include Enumerable

  def initialize
    @items = []
  end

  def <<(item)
    @items << item
    self
  end

  def each
    return to_enum(:each) unless block_given?

    @items.each { |item| yield item }
    self
  end
end

list = TodoList.new << "wash" << "shop" << "cook"
list.each.with_index(1) { |item, n| puts "#{n}. #{item}" }
p list.select { |i| i.include?("o") }

Đầu ra:

1. wash
2. shop
3. cook
["shop", "cook"]

block_given? cho biết bên gọi có truyền một khối lệnh hay không. Enumerator được trả về khi không có khối lệnh hỗ trợ nối chuỗi, chẳng hạn như each.with_index, each_slice hoặc next:

class Countdown
  include Enumerable

  def initialize(from)
    @from = from
  end

  def each
    return to_enum(:each) unless block_given?

    @from.downto(1) { |n| yield n }
  end
end

e = Countdown.new(3).each
puts e.next
puts e.next
p Countdown.new(5).each_slice(2).to_a

Đầu ra:

3
2
[[5, 4], [3, 2], [1]]

to_s là văn bản thân thiện dành cho người dùng, còn inspect là phần tóm tắt ngắn dành cho lập trình viên. Với một tập hợp, inspect thường hiển thị lớp và kích thước thay vì từng phần tử:

class TodoList
  include Enumerable

  def initialize(*items)
    @items = items
  end

  def each(&block)
    @items.each(&block)
  end

  def size
    @items.size
  end

  def to_s
    map.with_index(1) { |item, n| "#{n}. #{item}" }.join("\n")
  end

  def inspect
    "#<TodoList #{size} items>"
  end
end

list = TodoList.new("wash", "shop")
puts list
p list

Đầu ra:

1. wash
2. shop
#<TodoList 2 mục>

Enumerable cung cấp count, nhưng không cung cấp size, empty?, << hoặc []: những phương thức đó thuộc về lớp, vì chỉ lớp mới biết các phần tử được lưu trữ như thế nào. Định nghĩa chúng giúp bộ sưu tập hoạt động như một mảng đối với nơi gọi chúng:

def size
  @items.size
end

def empty?
  @items.empty?
end

def [](index)
  @items[index]
end
challenge icon

Thử thách

Dễ

Hoàn thiện lớp TodoList. << thêm nội dung của một công việc và trả về danh sách. each lần lượt đưa ra các công việc và trả về to_enum(:each) nếu không có khối lệnh. Bao gồm Enumerable. size trả về số lượng công việc. to_s trả về các công việc dưới dạng những dòng được đánh số, 1. wash, hoặc nothing to do, còn inspect trả về #<TodoList 3 items>.

Code được cung cấp thêm từng dòng đầu vào bằng cách nối chuỗi <<, sau đó in danh sách, p của danh sách, các công việc được đánh số bằng ! thông qua each.with_index(1) như 1! wash, số lượng công việc có chứa o và công việc đầu tiên theo thứ tự bảng chữ cái.

Đặt code của bạn trong todo_list.rb. main.rb chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.

Tự làm thử

require_relative 'todo_list'

# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
input = []
while (line = gets)
  input << line.chomp
end
list = input.reduce(TodoList.new) { |l, task| l << task }
puts list
p list
list.each.with_index(1) { |task, n| puts "#{n}! #{task}" }
puts "with o: #{list.count { |t| t.include?("o") }}"
puts "first: #{list.min}"
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Ruby online