Присваивание
В 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 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]
Это неявным образом создаёт массив.
Вы можете использовать * или оператор «распаковки» или распаковать массив при присваивании. Это аналогично множественному присваиванию:
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}
Но вы можете использовать только один * в присваивании.
Разложение массива
Как и разложение массива в аргументах методов, вы можете разложить массив во время присваивания с использованием скобок:
(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.