• В Ruby константы не являются истинно неизменными. Их нельзя изменять в теле методов экземпляра, но из других мест это вполне возможно.
• Ключевое слово yield
пришло из языка CLU и некоторым программистам может быть непонятно. Оно используется внутри итератора, чтобы передать управление блоку, с которым итератор был вызван. В данном случае yield
не означает, что нужно получить результат или вернуть значение. Скорее, речь идет о том, чтобы уступить процессор для работы.
• Составные операторы присваивания +=
, -=
и пр. — это не методы (собственно, это даже не операторы). Это всего лишь «синтаксическая глазурь» или сокращенная форма записи более длинной формы. Поэтому x += y
значит в точности то же самое, что x = x + y
. Если оператор +
перегружен, то оператор +=
«автоматически» учитывает новую семантику.
• Из-за того, как определены составные операторы присваивания, их нельзя использовать для инициализации переменных. Если первое обращение к переменной x
выглядит как x += 1
, возникнет ошибка. Это интуитивно понятно для программистов, если только они не привыкли к языку, в котором переменные автоматически инициализируются нулем или пустым значением.
• Такое поведение можно в некотором смысле обойти. Можно определить операторы для объекта nil
, так что в случае, когда начальное значение переменной равно nil
, мы получим желаемый результат. Так, метод nil.+
, приведенный ниже, позволит инициализировать объект типа string
или Fixnum
, для чего достаточно вернуть аргумент other
. Таким образом, nil + other
будет равно other
.
def nil.+(other)
other
end
Мы привели этот код для иллюстрации возможностей Ruby, но стоит ли поступать так на практике, оставляем на усмотрение читателя.
• Уместно будет напомнить, что Class
— это объект, a Object
— это класс. Мы попытаемся прояснить этот вопрос в следующей главе, а пока просто повторяйте это как мантру.
• Некоторые операторы нельзя перегружать, потому что они встроены в сам язык, а не реализованы в виде методов. К таковым относятся =
, ..
, ...
, and
, or
, not
, &&
, ||
, !
, !=
и !~
. Кроме того, нельзя перегружать составные операторы присваивания (+=
, -=
и т.д.). Это не методы и, пожалуй, даже не вполне операторы.
• Имейте в виду, что хотя оператор присваивания перегружать нельзя, тем не менее возможно написать метод экземпляра с именем fоо=
(тогда станет допустимым предложение x.foo = 5
). Можете рассматривать знак равенства как суффикс.
• Напомним: «голый» оператор разрешения области видимости подразумевает наличие Object
перед собой, то есть ::Foo
— то же самое, что Objеct::Foo
.
• Как уже говорилось, fail
— синоним raise
.
• Напомним, что определения в Ruby исполняются. Вследствие динамической природы языка можно, например, определить два метода совершенно по-разному в зависимости от значения признака, проверяемого во время выполнения.
• Напомним, что конструкция for (for x in а)
на самом деле вызывает итератор each
. Любой класс, в котором такой итератор определен, можно обходить в цикле for
.
• Не забывайте, что метод, определенный на верхнем уровне, добавляется в модуль Kernel
и, следовательно, становится членом класса Object
.
• Методы установки (например, fоо=
) должны вызываться от имени объекта, иначе анализатор решит, что речь идет о присваивании переменной с таким именем.
• Напомним, что ключевое слово retry
можно использовать в итераторах, но не в циклах общего вида. В контексте итератора оно заставляет заново инициализировать все параметры и возобновить текущую итерацию с начала.
• Ключевое слово retry
применяется также при обработке исключений. Не путайте два этих вида использования.
• Метод объекта initialize
всегда является закрытым.
• Когда итератор заканчивается левой фигурной скобкой (или словом end
) и возвращает значение, это значение можно использовать для вызова последующих методов, например:
squares = [1,2,3,4,5].collect do |x| x**2 end.reverse
# squares теперь равно [25,16,9,4,1]
• В конце программы на Ruby часто можно встретить идиому
if $0 == __FILE__
Таким образом проверяется, исполняется ли файл как автономный кусок кода (true
) или как дополнительный, например библиотека (false
). Типичное применение — поместить некую «главную программу» (обычно с тестовым кодом) в конец библиотеки.
• Обычное наследование (порождение подкласса) обозначается символом <
:
class Dog < Animal
# ...
end
Однако для создания синглетного класса (анонимного класса, который расширяет единственный экземпляр) применяется символ <<
:
class << platypus
# ...
end
• При передаче блока итератору есть тонкое различие между фигурными скобками ({}
) и операторными скобками do-end
. Связано оно с приоритетом:
mymethod param1, foobar do ... end
# Здесь do-end связано с mymethod.
mymethod param1, foobar { ... }
# А здесь {} связано с именем foobar, предполагается, что это метод.
• Традиционно в Ruby однострочные блоки заключают в фигурные скобки, а многострочные — в скобки do-end, например:
my_array.each { |x| puts x }
my_array.each do |x|
print x
if x % 2 == 0
puts ' четно.'
else
puts ' нечетно.'
end
end
Это необязательно и в некоторых случаях даже нежелательно.
• Помните, что строки (strings) в некотором смысле двулики: их можно рассматривать как последовательность символов или как последовательность строчек (lines). Кому-то покажется удивительным, что итератор each
оперирует строками (здесь под «строкой» понимается