Присвоение
В 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, «неопределённая локальная переменная или метод '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]]
Переменные экземпляров
Переменные экземпляров разделяются между всеми методами для одного и того же объекта.
Переменная экземпляра должна начинаться со знака @ («@»). В противном случае имена переменных экземпляров следуют правилам, как имена локальных переменных. Поскольку переменная экземпляра начинается со знака @, второй символ может быть заглавной буквой.
Вот пример использования переменных экземпляров:
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 Переменные
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.
Неявное присваивание 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–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.