Модуль Comparable
Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 29 из 57.
Встроенный модуль Ruby Comparable предоставляет классу операторы <, <=, ==, >, >= и методы between? и clamp. Для его работы в классе должен быть определён один метод: <=>, который возвращает отрицательное число, 0 или положительное число, когда объект меньше, равен или больше:
class Weight
include Comparable
attr_reader :grams
def initialize(grams)
@grams = grams
end
def <=>(other)
grams <=> other.grams
end
end
a = Weight.new(500)
b = Weight.new(1200)
puts a < b
puts a == Weight.new(500)
puts b.between?(a, Weight.new(2000))Результат:
true
true
trueЧисла и строки уже поддерживают <=>, поэтому класс обычно делегирует сравнение одному из своих значений. Сравнение массивов выполняется поэлементно, что позволяет сортировать сразу по нескольким полям:
class Person
include Comparable
attr_reader :last, :first
def initialize(first, last)
@first = first
@last = last
end
def <=>(other)
[last, first] <=> [other.last, other.first]
end
end
a = Person.new("Ada", "Lovelace")
b = Person.new("Alan", "Turing")
c = Person.new("Byron", "Lovelace")
puts a < c
puts b > cРезультат:
true
truesort, min и max также используют <=>, поэтому объекты класса можно сортировать без блока. clamp удерживает значение между двумя другими:
class Weight
include Comparable
attr_reader :grams
def initialize(grams)
@grams = grams
end
def <=>(other)
grams <=> other.grams
end
def to_s
"#{grams}g"
end
end
list = [Weight.new(900), Weight.new(150), Weight.new(400)]
puts list.sort.join(", ")
puts list.max
puts Weight.new(5000).clamp(Weight.new(0), Weight.new(1000))Вывод:
150g, 400g, 900g
900g
1000g<=> должен возвращать nil, если другой объект нельзя сравнить. Затем Comparable вызывает ArgumentError для < и возвращает false для ==, вместо того чтобы завершаться с запутывающей ошибкой NoMethodError:
def <=>(other)
return nil unless other.is_a?(Weight)
grams <=> other.grams
end
Weight.new(1) == 5 # false
Weight.new(1) < 5 # ArgumentError: comparison of Weight with 5 failedЗадание
ЛегкоЗавершите класс Weight. Weight.parse(text) считывает 500g, 1.2kg или 2lb (1 lb — это 453.6 g) и сохраняет значение в граммах. Подключите Comparable и определите <=> для граммов. to_s возвращает количество граммов, округлённое до целого числа, например 1200g.
Предоставленный код разбирает каждую входную строку, затем выводит веса в отсортированном порядке, самый большой и самый маленький вес, информацию о том, находится ли первый вес между 1 кг и 2 кг, а также первый вес, ограниченный сверху значением не более 1 кг.
Ваш код должен находиться в weight.rb. В main.rb содержится предоставленный код ввода/вывода, и его нельзя изменять.
Попробуйте сами
require_relative 'weight'
# Предоставленный код ввода/вывода: оставьте его как есть
input = []
while (line = gets)
input << line.chomp
end
weights = input.map { |line| Weight.parse(line) }
puts "sorted: #{weights.sort.join(", ")}"
puts "heaviest: #{weights.max}"
puts "lightest: #{weights.min}"
puts "first between 1kg and 2kg: #{weights[0].between?(Weight.parse("1kg"), Weight.parse("2kg"))}"
puts "first clamped: #{weights[0].clamp(Weight.parse("0g"), Weight.parse("1kg"))}"
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовПеременные экземпляраМетоды и selfto_s и inspectПовторение — читательский билет4Инкапсуляция
Приватные методыЗащищённые методыПриватные сеттерыЗащита состоянияПовторение — торговый автомат7Полиморфизм и утиная типизация
ПолиморфизмУтиная типизацияАбстрактные методыcase и классыПовторение — способы оплаты10Шаблоны проектирования, часть 2
Делегирование с помощью ForwardableШаблон декоратораШаблон строителяШаблон состояния2Аксессоры и self
Чтение и записьПользовательские сеттерыself в методахИдентичность и равенствоПовторение — список контактов5Наследование
ПодклассыПереопределение методовВызов superis_a? и предкиПовторение — расчёт зарплаты сотрудников8Специальные методы
Равенство и хешированиеМетоды операторовИндексация и добавлениеПользовательские коллекцииПовторение — дроби11Проект: Управление библиотекой
Книги и читателиВыдача книг3Методы и переменные классов
Методы классовПеременные экземпляра классаКонстантыФабричные методыПовторение — коды купонов6Модули и примеси
Модули и includeРасширение объектовМодуль ComparableМодуль EnumerableПовторение — спортивная лига9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Онлайн-компилятор Ruby