Присваивание
В 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, если метод не является общедоступным или получателем служит литерал self.
Ещё один частый источник путаницы — использование модификатора if:
p a if a = 0.zero?
Вместо вывода «true» вы получите исключение NameError: «undefined local variable or method ‘a’» («не определена локальная переменная или метод ‘a’»). Поскольку Ruby сначала разбирает отдельное a слева от if и ещё не встретил присваивания a, он решает, что вы хотите вызвать метод. Затем Ruby встречает присваивание a и предполагает, что вы обращаетесь к локальной переменной.
Путаница возникает из-за выполнения выражения не по порядку. Сначала локальной переменной присваивается значение, а затем вы пытаетесь вызвать несуществующий метод.
Локальные переменные и eval
Использование eval для вычисления кода Ruby позволяет обращаться к локальным переменным, определённым в той же области видимости, даже если они определены уже после вызова eval. Однако локальные переменные, определённые внутри вызова eval, не будут видны во внешней области видимости. Внутри вызова eval доступны локальные переменные, определённые во внешней области видимости, а также переменные, определённые внутри вызова eval. Однако нельзя получить доступ к локальным переменным, определённым в предыдущих или последующих вызовах eval в той же области видимости. Считайте каждый вызов eval отдельной вложенной областью видимости. Пример:
def m eval "bar = 1" lvs = eval "baz = 2; ary = [local_variables, foo, baz]; x = 2; ary" eval "quux = 3" foo = 1 lvs << local_variables end m # => [[:baz, :ary, :x, :lvs, :foo], nil, 2, [:lvs, :foo]]
Переменные экземпляра
Переменные экземпляра являются общими для всех методов одного и того же объекта.
Имя переменной экземпляра должно начинаться с @ (символа «собака» или коммерческого at). В остальном имена переменных экземпляра подчиняются тем же правилам, что и имена локальных переменных. Поскольку имя переменной экземпляра начинается с @, второй символ может быть заглавной буквой.
Пример использования переменной экземпляра:
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.
Метод value имеет доступ к значению, заданному методом initialize, но только для того же объекта.
Переменные класса
Переменные класса являются общими для класса, его подклассов и экземпляров.
Имя переменной класса должно начинаться с @@ (двух символов «собака»). Остальная часть имени подчиняется тем же правилам, что и для переменных экземпляра.
Пример:
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.
Неявное присваивание Array
При присваивании можно неявно создать массив, перечислив несколько значений:
a = 1, 2, 3 p a # prints [1, 2, 3]
Так неявно создаётся Array.
При присваивании можно использовать *, оператор «splat» или распаковать Array. Это похоже на множественное присваивание:
a = *[1, 2, 3] p a # prints [1, 2, 3] b = *1 p b # prints [1]
Оператор «splat» можно использовать в любом месте правой части присваивания:
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: разложение
Как и при разложении Array в аргументах метода, при присваивании можно разложить Array, используя круглые скобки:
(a, b) = [1, 2]
p a: a, b: b # prints {:a=>1, :b=>2}
Можно разложить Array как часть более крупного множественного присваивания:
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–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.