Spec-Zone.ru › Ruby 3

Присваивание

В 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, если видимость метода не public, или если получатель является буквальным 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. Если вы запустите 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]

Это неявно создает массив.

Вы можете использовать * или оператор «splat» или распаковать массив при присваивании. Это аналогично множественному присваиванию:

a = *[1, 2, 3]

p a # prints [1, 2, 3]

Вы можете использовать оператор «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 Разбиение массива

Подобно разбиению массива в аргументах методов, вы можете разбить массив во время присваивания с использованием скобок:

(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–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API