Присваивание
В Ruby присваивание выполняется с помощью символа = (знак равенства). В этом примере числу пять присваивается локальная переменная v:
v = 5
Присваивание создаёт локальную переменную, если переменная ранее не использовалась.
Имена локальных переменных
Имя локальной переменной должно начинаться с буквы нижнего регистра US-ASCII или символа с установленным восьмым битом. Как правило, локальные переменные совместимы с US-ASCII, поскольку клавиши для их ввода есть на всех клавиатурах.
(Программы Ruby должны быть написаны в наборе символов, совместимом с US-ASCII. В таких наборах символов, если установлен восьмой бит, это указывает на расширенный символ. Ruby позволяет локальным переменным содержать такие символы.)
Имя локальной переменной может содержать буквы, цифры, символ _ (подчёркивание) или символ с установленным восьмым битом.
Область действия локальных переменных
После присваивания имени локальной переменной все последующие использования этого имени в той же области действия рассматриваются как локальные переменные.
Вот пример:
1.times do
a = 1
puts "local variables in the block: #{local_variables.join ", "}"
end
puts "no local variables outside the block" if local_variables.empty?
Это выводит:
local variables in the block: a no local variables outside the block
Поскольку блок создаёт новую область действия, любые локальные переменные, созданные внутри него, не влияют на окружающую область действия.
Переменные, определённые во внешней области действия, видны во внутренней области действия:
a = 0
1.times do
puts "local variables: #{local_variables.join ", "}"
end
Это выводит:
local variables: a
Вы можете изолировать переменные в блоке от внешней области действия, перечислив их после ; в аргументах блока. См. документацию по локальным переменным блоков в документации вызова методов для примера.
См. также Kernel#local_variables, но обратите внимание, что цикл for не создаёт новой области действия, как блок.
Локальные переменные и методы
В Ruby имена локальных переменных и имен методов практически идентичны. Если вы не присвоили значение одному из этих неоднозначных имён, Ruby предположит, что вы хотите вызвать метод. После присваивания значения имени Ruby предположит, что вы хотите обратиться к локальной переменной.
Локальная переменная создаётся при встрече парсером присваивания, а не при самом присваивании:
a = 0 if false # does not assign to a p local_variables # prints [:a] p a # prints nil
Сходство между именами методов и локальных переменных может привести к запутанному коду, например:
def big_calculation 42 # pretend this takes a long time end big_calculation = big_calculation()
Теперь любое обращение к big_calculation рассматривается как локальная переменная и будет кэшировано. Чтобы вызвать метод, используйте self.big_calculation.
Вы можете принудительно вызвать метод, используя пустые скобки аргументов, как показано выше, или используя явный получатель, например, self.. Использование явного получателя может вызвать NameError, если видимость метода не является общедоступной.
Ещё один часто запутанный случай — использование модификатора if:
p a if a = 0.zero?
Вместо вывода «true» вы получите NameError, «неопределённая локальная переменная или метод `a'». Так как Ruby анализирует простое a слева от if первым и ещё не видел присваивания a, он предполагает, что вы хотите вызвать метод. Затем Ruby видит присваивание a и предположит, что вы ссылаетесь на локальный метод.
Затруднение возникает из-за выполнения выражения в неправильном порядке. Сначала локальной переменной присваивается значение, а затем вы пытаетесь вызвать несуществующий метод.
Переменные экземпляра
Переменные экземпляра разделяются между всеми методами для одного и того же объекта.
Переменная экземпляра должна начинаться с @ (символ «собаки» или коммерческий символ «собаки»). В противном случае имена переменных экземпляров следуют правилам имён локальных переменных. Поскольку переменная экземпляра начинается с @ , второй символ может быть заглавной буквой.
Вот пример использования переменной экземпляра:
class C
def initialize(value)
@instance_variable = value
end
def value
@instance_variable
end
end
object1 = C.new "some value"
object2 = C.new "other value"
p object1.value # prints "some value"
p object2.value # prints "other value"
Неинициализированная переменная экземпляра имеет значение nil. Если вы запускаете Ruby с включёнными предупреждениями, при обращении к неинициализированной переменной экземпляра будет выдано предупреждение.
Метод value имеет доступ к значению, установленному методом initialize , но только для того же объекта.
Class Переменные
Class переменные разделяются между классом, его подклассами и его экземплярами.
Переменная класса должна начинаться с @@ (двух символов «собаки»). Остальная часть имени следует тем же правилам, что и переменные экземпляра.
Вот пример:
class A
@@class_variable = 0
def value
@@class_variable
end
def update
@@class_variable = @@class_variable + 1
end
end
class B < A
def update
@@class_variable = @@class_variable + 2
end
end
a = A.new
b = B.new
puts "A value: #{a.value}"
puts "B value: #{b.value}"
Это выводит:
A value: 0 B value: 0
Продолжая тот же пример, мы можем обновить значения, используя объекты из любого класса, и значение делится:
puts "update A"
a.update
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "update B"
b.update
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "update A"
a.update
puts "A value: #{a.value}"
puts "B value: #{b.value}"
Это выводит:
update A A value: 1 B value: 1 update B A value: 3 B value: 3 update A A value: 4 B value: 4
Обращение к неинициализированной переменной класса вызовет исключение NameError.
Обратите внимание, что классы имеют переменные экземпляра, поскольку классы — это объекты, поэтому старайтесь не путать переменные класса и экземпляра.
Глобальные переменные
Глобальные переменные доступны повсюду.
Глобальные переменные начинаются с $ (знак доллара). Остальная часть имени следует тем же правилам, что и переменные экземпляра.
Вот пример:
$global = 0
class C
puts "in a class: #{$global}"
def my_method
puts "in a method: #{$global}"
$global = $global + 1
$other_global = 3
end
end
C.new.my_method
puts "at top-level, $global: #{$global}, $other_global: #{$other_global}"
Это выводит:
in a class: 0 in a method: 0 at top-level, $global: 1, $other_global: 3
Неинициализированная глобальная переменная имеет значение nil.
Ruby имеет некоторые специальные глобальные переменные, поведение которых зависит от контекста, такие как переменные сопоставления регулярных выражений или которые вызывают побочный эффект при присваивании. См. документацию по глобальным переменным для получения подробностей.
Методы присваивания
Вы можете определить методы, которые будут вести себя как присваивание, например:
class C
def value=(value)
@value = value
end
end
c = C.new
c.value = 42
Использование методов присваивания позволяет сделать ваши программы более удобочитаемыми. При присваивании переменной экземпляра большинство людей используют Module#attr_accessor:
class C attr_accessor :value end
При использовании метода присваивания вы всегда должны иметь получатель. Если у вас нет получателя, Ruby предполагает, что вы присваиваете локальной переменной:
class C
attr_accessor :value
def my_method
value = 42
puts "local_variables: #{local_variables.join ", "}"
puts "@value: #{@value.inspect}"
end
end
C.new.my_method
Это выводит:
local_variables: value @value: nil
Чтобы использовать метод присваивания, вы должны установить получателя:
class C
attr_accessor :value
def my_method
self.value = 42
puts "local_variables: #{local_variables.join ", "}"
puts "@value: #{@value.inspect}"
end
end
C.new.my_method
Это выводит:
local_variables: @value: 42
Сокращённое присваивание
Вы можете комбинировать несколько операторов и присваивание. Чтобы добавить 1 к объекту, вы можете написать:
a = 1 a += 2 p a # prints 3
Это эквивалентно:
a = 1 a = a + 2 p a # prints 3
Вы можете использовать следующие операторы таким образом: +, -, *, /, %, **, &, |, ^, <<, >>
Также существуют ||= и &&= . Первый выполняет присваивание, если значение было nil или false , а второй выполняет присваивание, если значение не было nil или false.
Вот пример:
a ||= 0 a &&= 1 p a # prints 1
Обратите внимание, что эти два оператора ведут себя скорее как a || a = 0 , чем как a = a || 0.
Неявное присваивание массива
Вы можете неявным образом создать массив, перечислив несколько значений при присваивании:
a = 1, 2, 3 p a # prints [1, 2, 3]
Это неявно создаёт Array.
Вы можете использовать * или оператор «разбрасывания» или распаковать Array при присваивании. Это похоже на множественное присваивание:
a = *[1, 2, 3] p a # prints [1, 2, 3]
Вы можете использовать разбрасывание где угодно в правой части присваивания:
a = 1, *[2, 3] p a # prints [1, 2, 3]
Множественное присваивание
Вы можете присвоить несколько значений справа к нескольким переменным слева:
a, b = 1, 2
p a: a, b: b # prints {:a=>1, :b=>2}
В следующих разделах в любом месте, где используется «переменная», также будут работать методы присваивания, экземпляры, классы или глобальные переменные:
def value=(value)
p assigned: value
end
self.value, $global = 1, 2 # prints {:assigned=>1}
p $global # prints 2
Вы можете использовать множественное присваивание, чтобы поменять местами два значения:
old_value = 1
new_value, old_value = old_value, 2
p new_value: new_value, old_value: old_value
# prints {:new_value=>1, :old_value=>2}
Если у вас справа больше значений, чем переменных слева, дополнительные значения игнорируются:
a, b = 1, 2, 3
p a: a, b: b # prints {:a=>1, :b=>2}
Вы можете использовать * , чтобы собрать дополнительные значения в правой части присваивания.
a, *b = 1, 2, 3
p a: a, b: b # prints {:a=>1, :b=>[2, 3]}
* может появляться в любом месте слева:
*a, b = 1, 2, 3
p a: a, b: b # prints {:a=>[1, 2], :b=>3}
Но вы можете использовать только один * в одном присваивании.
Array Разбиение массива
Как и разбиение массива в аргументах методов, вы можете разбить массив во время присваивания, используя скобки:
(a, b) = [1, 2]
p a: a, b: b # prints {:a=>1, :b=>2}
Вы можете разбить массив как часть более сложного множественного присваивания:
a, (b, c) = 1, [2, 3]
p a: a, b: b, c: c # prints {:a=>1, :b=>2, :c=>3}
Поскольку каждое разбиение считается отдельным множественным присваиванием, вы можете использовать * для сбора аргументов в разбиении:
a, (b, *c), *d = 1, [2, 3, 4], 5, 6
p a: a, b: b, c: c, d: d
# prints {:a=>1, :b=>2, :c=>[3, 4], :d=>[5, 6]}
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.