Кстати, не рекомендуем создавать структуру с именем Tms
, так как уже есть предопределенный класс Struct::Tms
.
11.1.15. Замораживание объектов
Иногда необходимо воспрепятствовать изменению объекта. Это позволяет сделать метод freeze
(определенный в классе Object
). По существу, он превращает объект в константу.
Попытка модифицировать замороженный объект приводит к исключению TypeError
. В листинге 11.8 приведено два примера.
Листинг 11.8. Замораживание объекта
str = "Это тест. "
str.freeze
begin
str << " He волнуйтесь." # Попытка модифицировать.
rescue => err
puts "#{err.class} #{err}"
end
arr = [1, 2, 3]
arr.freeze
begin
arr << 4 # Попытка модифицировать.
rescue => err
puts "#{err.class} #{err}"
end
# Выводится:
# TypeError: can't modify frozen string
# TypeError: can't modify frozen array
Однако имейте в виду, что метод freeze
применяется к ссылке на объект, а не к переменной! Это означает, что любая операция, приводящая к созданию нового объекта, завершится успешно. Иногда это противоречит интуиции. В примере ниже мы ожидаем, что операция +=
не выполнится, но все работает нормально. Дело в том, что присваивание — не вызов метода. Эта операция воздействует на переменные, а не на объекты, поэтому новый объект создается беспрепятственно. Старый объект по-прежнему заморожен, но переменная ссылается уже не на него.
str = "counter-"
str.freeze
str += "intuitive" # "counter-intuitive"
arr = [8, 6, 7]
arr.freeze
arr += [5, 3, 0, 9] # [8, 6, 7, 5, 3, 0, 9]
Почему так происходит? Предложение a += x
семантически эквивалентно a = a + x
. При вычислении выражения a + x
создается новый объект, который затем присваивается переменной a
! Все составные операторы присваивания работают подобным образом, равно как и другие методы. Всегда задавайте себе вопрос: «Что я делаю — создаю новый объект или модифицирую существующий?» И тогда поведение freeze
не станет для вас сюрпризом.
Существует метод frozen?
, который сообщает, заморожен ли данный объект.
hash = { 1 => 1, 2 => 4, 3 => 9 }
hash.freeze
arr = hash.to_a
puts hash.frozen? # true
puts arr.frozen? # false
hash2 = hash
puts hash2.frozen? # true
Как видите (на примере hash2
), замораживается именно объект, а не переменная.
11.2. Более сложные механизмы
Не все в модели ООП, реализованной в Ruby, одинаково очевидно. Что-то сложнее, что-то применяется реже. Линия раздела для каждого программиста проходит в разных местах. В этой части главы мы попытались собрать те средства, которые не так просты или не так часто встречаются в программах.
Иногда вы задаетесь вопросом, можно ли решить на Ruby ту или иную задачу. Краткий ответ таков: Ruby — богатый, динамический, объектно-ориентированный язык с широким набором разумно ортогональных средств; если нечто можно сделать на каком-то другом языке, то, скорее всего, можно и на Ruby.
Теоретически все полные по Тьюрингу языки более или менее одинаковы. Весь смысл проектирования языков в поиске осмысленной, удобной нотации. Читателю, сомневающемуся в важности нотации, стоит попробовать написать интерпретатор LISP на языке COBOL или выполнить деление чисел, записанных римскими цифрами.
Конечно, мы не хотим сказать, что любая задача на Ruby решается элегантно или естественно. Попытайся мы высказать такое утверждение, кто-нибудь очень быстро докажет, что мы не правы.
В этом разделе мы поговорим также о реализации на Ruby различных стилей программирования, например функционального и аспектно-ориентированного. Мы не претендуем на роль экспертов в этих областях, просто приводим мнение других. Относитесь к этому с долей скепсиса.
11.2.1. Отправка объекту явного сообщения
В статическом языке вы считаете очевидным, что имя вызываемой функции «зашито» в программу, это часть исходного текста. Динамический язык обладает в данном отношении большей гибкостью.
При любом вызове метода вы посылаете объекту сообщение. Обычно эти сообщения так же жестко «зашиты» в код, как и в статическом языке, но это необязательно. Можно написать программу, которая во время выполнения решает, какой метод вызывать. Метод send
позволяет использовать Symbol
для представления имени метода.
Пусть, например, имеется массив объектов, который нужно отсортировать, причем в качестве ключей сортировки хотелось бы использовать разные поля. Не проблема - можно просто написать специализированные блоки для сортировки. Но хотелось бы найти более элегантное решение, позволяющее обойтись одной процедурой, способной выполнить сортировку по любому указанному ключу. В листинге 11.9 такое решение приведено.
Читать дальше
Конец ознакомительного отрывка
Купить книгу