• Напомним, что ключевое слово 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
оперирует строками (здесь под «строкой» понимается группа символов, завершающаяся разделителем записей, который по умолчанию равен символу новой строки). У each
есть синоним each_line
. Если вы хотите перебирать символы, можете воспользоваться итератором each_byte
. Итератор sort
также оперирует строками. Для строк (strings) не существует итератора each_index
из-за возникающей неоднозначности. Действительно, хотим ли мы обрабатывать строку посимвольно или построчно? Все это со временем войдет в привычку.
• Замыкание (closure) запоминает контекст, в котором было создано. Один из способов создать замыкание — использование объекта Proc
. Например:
def power(exponent)
proc {|base| base**exponent}
end
square = power(2)
cube = power(3)
a = square.call(11) # Результат равен 121.
b = square.call(5) # Результат равен 25.
с = cube.call(6) # Результат равен 216.
d = cube.call(8) # Результат равен 512.
Обратите внимание, что замыкание «знает» значение показателя степени, переданное ему в момент создания.
• Однако помните: в замыкании используется переменная, определенная во внешней области видимости (что вполне допустимо). Это свойство может оказаться полезным, но приведем пример неправильного использования:
$exponent = 0
def power
proc {|base| base**$exponent}
end
$exponent = 2
square = power
$exponent = 3
cube = power
a = square.call(11) # Неверно! Результат равен 1331.
b = square.call(5) # Неверно! Результат равен 125.
# Оба результата неверны, поскольку используется ТЕКУЩЕЕ
# значение $exponent. Так было бы даже в том случае, когда
# используется локальная переменная, покинувшая область
# видимости (например, с помощью define_method).
с = cube.call(6) # Результат равен 216.
d = cube.call(8) # Результат равен 512.