def mymethod
@x = 3 # Переменная экземпляра.
# Заметим, что в этой точке @y недоступна.
end
end
Переменная экземпляра класса (@y в предыдущем примере - в действительности атрибут объекта класса Myclass, являющегося экземпляром класса Class. (Напомним, что Class - это объект, a Object - это класс.) На переменные экземпляра класса нельзя ссылаться из методов экземпляра и, вообще говоря, они не очень полезны.
• attr, attr_reader, attr_writer и attr_accessor - сокращенная запись для определения методов чтения и установки атрибутов. В качестве аргументов они принимают символы (экземпляры класса Symbol).
• Присваивание переменной, имя которой содержит оператор разрешения области видимости, недопустимо. Например, Math::Pi = 3.2 - ошибка.
1.5.5. Ориентация на выражения и прочие вопросы
В Ruby выражения важны почти так же, как предложения. Для программиста на С это звучит знакомо, а для программиста на Pascal - откровенная нелепость. Но Ruby ориентирован на выражения даже в большей степени, чем С.
Заодно в этом разделе мы остановимся на паре мелких вопросов, касающихся регулярных выражений; считайте это небольшим бонусом.
• В Ruby любое присваивание возвращает то же значение, которое стоит в правой части. Поэтому иногда мы можем немного сократить код, как показано ниже, но будьте осторожны, имея дело с объектами! Не забывайте, что это почти всегда ссылки.
x = y = z = 0 # Все переменные сейчас равны 0.
а = b = с = [] # Опасно! a, b и с ссылаются
# на ОДИН И ТОТ ЖЕ пустой массив.
x = 5
y = x += 2 # Сейчас x и у равны 7.
Напомним однако, что значения типа Fixnum и им подобные хранятся непосредственно, а не как ссылки на объекты.
• Многие управляющие конструкции возвращают значения, в частности if, unless и case. Следующий код корректен; он показывает, что при принятии решения ветви могут быть выражениями, а не полноценными предложениями.
а = 5
x = if а < 8 then 6 else 7 end # x равно 6.
y= if a<8 # y тоже равно 6;
6 # предложение if может располагаться
else # на одной строке
7 # или на нескольких.
end
# unless тоже работает; z присваивается значение 4.
z = unless x == y then 3 else 4 end
t = case a # t получает
when 0..3 # значение
"low" # medium,
when 4..6
"medium"
else
"high"
end
Здесь мы сделали такие отступы, будто case является присваиванием. Мы воспринимаем такую запись спокойно, хотя вам она может не понравиться.
• Отметим, что циклы while и until, напротив, не возвращают никаких полезных значений; обычно их значением является nil:
i = 0
x = while (i < 5) # x равно nil.
puts i+=1
end
• Тернарный оператор можно использовать как в предложениях, так и в выражениях. В силу синтаксических причин (или ограничений анализатора) скобки здесь обязательны:
x = 6
y = x == 5 ? 0 : 1 #y равно 1.
x == 5 ? puts("Привет") : puts("Пока") # Печатается: "Пока"
• Предложение return в конце метода можно опускать. Метод всегда возвращает значение последнего вычисленного выражения, в каком бы месте это вычисление ни происходило.
• Когда итератор вызывается с блоком, последнее выражение, вычисленное в блоке, возвращается в качестве значения блока. Если при этом в теле итератора есть предложение x = yield, то x будет присвоено это значение.
• Регулярные выражения. Напомним, что после регулярного выражения можно написать модификатор многострочности /m, и в этом случае точка (.) будет сопоставляться с символом новой строки.
• Регулярные выражения. Опасайтесь соответствий нулевой длины. Если все элементы регулярного выражения необязательны, то такому образцу будет соответствовать "ничто", причем соответствие всегда будет найдено в начале строки. Это типичная ошибка, особенно часто ее допускают новички.
1.6. Жаргон Ruby
Заново начинать учить английский для освоения Ruby необязательно. Но нужно знать кое-какие жаргонные выражения, обычные в сообществе. Некоторые из них имеют другой смысл, чем принято в компьютерном мире. Им и посвящен настоящий раздел.
В Ruby термин "атрибут" носит неофициальный характер. Можно считать, что атрибут - это переменная экземпляра, которая раскрывается внешнему миру с помощью одного из методов семейства attr. Но тут нет полной определенности: могут существовать методы foo и foo=, не соответствующие переменной @foo, как можно было бы ожидать. И, конечно, не все переменные экземпляра считаются атрибутами. Как обычно, нужно придерживаться здравого смысла.
Атрибуты в Ruby можно подразделить на методы чтения (reader) и установки (writer). Метод доступа, или акцессор (accessor), является одновременно методом чтения и установки. Это согласуется с названием метода attr_accessor, но противоречит принятой в других сообществах семантике, согласно которой акцессор дает доступ только для чтения.
Оператор === имеется только в Ruby (насколько мне известно). Обыкновенно он называется оператором ветвящегося равенства (case equality operator), поскольку неявно используется в предложениях case. Но это название, как я уже говорил, не вполне точно, потому что речь идет не только о "равенстве". В данной книге я часто употребляю термин "оператор отношения" (relationship operator). Изобрел его не я, но проследить происхождение мне не удалось, к тому же он употребляется нечасто. Жаргонное название - "оператор тройного равенства" (threequal operator) или просто "три равно".
Оператор <=>, наверное, лучше всего называть оператором сравнения. На жаргоне его называют космическим оператором (spaceship operator), поскольку он напоминает летающую тарелку - так ее изображали в старых видеоиграх.
Термин "поэтический режим" (poetry mode) подчеркивает, что можно опускать ненужные знаки препинания и лексемы (насмешливый намек на отношение поэтов к пунктуации на протяжении последних шестидесяти лет). Поэтический режим также часто означает "опускание скобок при вызове метода".
some_method(1, 2, 3) # Избыточные скобки.
some_method 1, 2, 3 # "Поэтический режим".
Но мне этот принцип представляется более общим. Например, когда хэш передается в качестве последнего или единственного параметра, можно опускать фигурные скобки. В конце строки можно не ставить точку с запятой (а потому никто этого и не делает). В большинстве случаев разрешается опускать ключевое слово then в предложениях if и case.
Некоторые программисты заходят еще дальше, опуская скобки даже в определении методов, но большинство так не поступает:
def my_method(a, b, с) # Можно и так: def my_method a, b, с
# ...
end
Стоит отметить, что в некоторых случаях сложность грамматики Ruby приводит к сбоям анализатора. Во вложенных вызовах методов скобки для ясности лучше оставлять. Иногда в текущей версии Ruby выводятся предупреждения:
def alpha(x)
x*2
end
def beta(y)
y*3
end
gamma = 5
delta = alpha beta gamma # 30 -- то же, что alpha(beta(gamma))
# Выдается предупреждение:
# warning: parenthesize argument(s) for future version
# предупреждение: заключайте аргумент(ы) в скобки для совместимости с
# с будущими версиями