Spec-Zone.ru › Ruby 3.1

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

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

v = 5

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

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

Имя локальной переменной должно начинаться с прописной буквы латинского алфавита или символа с установленным восьмым битом. Обычно локальные переменные совместимы с 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. Если вы запускаете 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.

Неявное присваивание Array

Вы можете неявно создать массив, перечислив несколько значений при присваивании:

a = 1, 2, 3

p a # prints [1, 2, 3]

Это неявно создаёт Array.

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

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 Разложение

Как и разложение 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–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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