Наверное, каждый, кто знает Ruby (сегодня), в прошлом изучал или пользовался
другими языками. Это, с одной стороны, облегчает изучение Ruby, так как многие средства похожи на аналогичные средства в других языках. С другой стороны, у
программиста может возникнуть ложное чувство уверенности при взгляде на знакомые
конструкции Ruby. Он может прийти к неверным выводам, основанным на
прошлом опыте; можно назвать это явление «багажом эксперта».
Немало специалистов переходит на Ruby со Smalltalk, Perl, C/C++ и других
языков. Ожидания этих людей сильно различаются, но так или иначе присутствуют.
Поэтому рассмотрим некоторые вещи, на которых многие спотыкаются.
• Символ в Ruby представляется целым числом. Это не самостоятельный тип,
как в Pascal, и не эквивалент строки длиной 1. В ближайшем будущем положение
изменится и символьная константа станет строкой, но на момент
написания данной книги этого еще не произошло. Рассмотрим следующий
фрагмент:
х = "Hello"
у = ?А >
puts "х[0] = #{х[0]}" # Печатается х[0] = 72
puts "у = #{у}" # Печатается у = 65
if у == "А" # Печатается по
puts "yes"
else
puts "no"
end
• He существует булевского типа. TrueClass и FalseClass - это два разных
класса, а единственными их экземплярами являются объекты true и false.
• Многие операторы в Ruby напоминают операторы в языке С. Два заметных
исключения - операторы инкремента и декремента (++ и --). Их в Ruby нет
ни в «пост», ни в «пред» форме.
• Известно, что в разных языках оператор деления по модулю работает по-
разному для отрицательных чисел. Не вдаваясь в споры о том, что правильно,
проиллюстрируем поведение в Ruby:
puts (5 % 3) # Печатается 2
puts (-5 % 3) # Печатается 1
puts (5 % -3) # Печатается -1
puts (-5 % -3) # Печатается -2
• Некоторые привыкли думать, что «ложь» можно представлять нулем, пустой
строкой, нулевым символом и т.п. Но в Ruby все это равно «истине».
На самом деле истиной будет все кроме объектов false и nil.
• В Ruby переменные не принадлежат никакому классу: класс есть только у
значений.
• Переменные в Ruby не объявляются, однако считается хорошим тоном присваивать
переменной начальное значение nil. Разумеется, при этом с переменной
не ассоциируется никакой тип и даже не происходит истинной инициализации,
но анализатор знает, что данное имя принадлежит переменной,
а не методу.
• ARGV [ 0 ] - первый аргумент в командной строке; они нумеруются начиная с
нуля. Это не имя файла или сценария, предшествующего параметрам, как
argv[0] в языке С.
• Большинство операторов в Ruby на самом деле является методами; их запись
в виде «знаков препинания» - не более чем удобство. Первое исключение из
этого правила - набор операторов составного присваивания (+=, -= и т.д.).
Второе исключение - операторы = !, not, &&, and, II, or, !=, !~.
• Как и в большинстве современных языков программирования (хотя и не во
всех), булевские операции закорачиваются, то есть вычисление булевского
выражения заканчивается, как только его значение истинности становится
известным. В последовательности операций or вычисление заканчивается,
когда получено первое значение true, а в последовательности операций
and - когда получено первое значение false.
• Префикс @@ применяется для переменных класса (то есть ассоциированных
с классом в целом, а не с отдельным экземпляром).
• loop - не ключевое слово. Это метод модуля Kernel, а не управляющая конструкция.
• Кому-то синтаксис unless-else может показаться интуитивно неочевидным.
Поскольку unless - противоположность if, то ветвь else выполняется,
когда условие истинно.
• Простой тип Fixnum передается как непосредственное значение и, стало
быть, не может быть изменен внутри метода. То же относится к значениям
true, false и nil.
• Не путайте операторы && и 11 с операторами & и I. Те и другие используются
в языке С; первые два предназначены для логических операций, последние
два - для поразрядных.
• Операторы and и or имеют более низкий приоритет, чем && и 11. Взгляните
на следующий фрагмент:
а = true
b = false
с = true
d = true
al = a && b or с && d
a2 = a && (b or c) && d
puts al
puts a2
# Операции && выполняются первыми.
# Операция or выполняется первой.
# Печатается false
# Печатается true
Не забывайте, что «оператор» присваивания имеет более высокий приоритет,
чем операторы and и or! (это относится и к составным операторам
присваивания: +=, -= и пр.). Например, код х = у or z выглядит как обычное
предложение присваивания, но на самом деле это обособленное выражение
(эквивалент (х=у) or z). Вероятно, программист имел в виду следующее: x
= (у or z).
у = false
z = true
x = у or z
puts x
# Оператор = выполняется РАНЬШЕ or!
# Печатается false
(x = у) or z
puts x
# Строка 5: то же, что и выше.
# Печатается fals
х = (у or z)
puts х
# Оператор or вычисляется сначала.
# Печатается true
• Не путайте атрибуты объектов с локальными переменными. Если вы привыкли
к С++ или Java, можете забыть об этом! Переменная @my_var в контексте
класса - это переменная экземпляра (или атрибут), но my_var в том
же контексте - локальная переменная.
• Во многих языках, и в Ruby в том числе, есть цикл for. Рано или поздно возникает
вопрос, можно ли модифицировать индексную переменную. В некоторых
языках эту управляющую переменную запрещено изменять вовсе
(выводится предупреждение либо сообщение об ошибке на этапе компиляции
или выполнения); в других это допустимо, хотя и приводит к изменению
поведения цикла. В Ruby принят третий подход. Переменная, управляющая
циклом for, считается обычной переменной, которую можно изменять в любой
момент, но это изменение не оказывает влияния на поведение цикла!
Цикл for присваивает этой переменной последовательные значения, что бы
с ней ни происходило внутри тела цикла. Например, следующий цикл будет
выполнен ровно 10 раз и напечатает значения от 1 до 10:
for var in 1..10
puts "var = #{var}" ••. -•
if var > 5
var = var + 2
end
• Имена переменных не всегда легко «на глаз» отличить от имен методов.
Как решает этот вопрос анализатор? Правило такое: если анализатор видит,
что идентификатору присваивается значение до его использования, то
он считается переменной; в противном случае это имя метода. (Отметим,
что операция присваивания может и не выполняться: достаточно того, что
интерпретатор ее видел.)
