Spec-Zone.ru › Ruby 2.4

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

В Ruby присваивание использует символ = (знак равенства). В этом примере числу пять присваивается локальная переменная v:

v = 5

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

Имена локальных переменных

Имя локальной переменной должно начинаться с строчной буквы ASCII или символа с установленным восьмым битом. Обычно локальные переменные совместимы с ASCII, так как клавиши для их ввода есть на всех клавиатурах.

(Программы Ruby должны быть написаны в наборе символов, совместимом с 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]

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

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

Но вы можете использовать только один * в присваивании.

Декомпозиция массива

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

(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.

Spec-Zone.ru

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