_If you wish to report errors or suggest improvements for this FAQ,
please go to our
[GitHub repository](https://github.com/ruby/www.ruby-lang.org/)
and open an issue or pull request._


## Змінні, константи та аргументи

### Чи створює присвоєння нову копію об’єкта?
{: #assignment}

Усі змінні та константи посилаються (вказують) на якийсь об’єкт.
(За винятком неініціалізованих локальних змінних, які ні на що не
посилаються. При використанні вони викликають виняток `NameError`.)
Коли ви присвоюєте значення змінній або ініціалізуєте константу, ви
встановлюєте об’єкт, на який вона посилається.

Отже, саме по собі присвоєння ніколи не створює нову копію об’єкта.

Є трохи глибше пояснення для певних особливих випадків. Екземпляри
`Fixnum`, `NilClass`, `TrueClass` і `FalseClass` зберігаються безпосередньо
в змінних або константах — посилання не використовується. Змінна, що
містить число `42`, або константа `true` фактично містить значення, а не
посилання на нього. Відповідно, присвоєння фізично створює копію об’єктів
цих типів. Детальніше про це — у
[Immediate and Reference Objects](../6/#immediate).

### Яка область видимості локальної змінної?

Нова область видимості для локальної змінної з’являється у:
(1) верхньому рівні (main),
(2) визначенні класу (або модуля), або
(3) визначенні методу.

~~~
var = 1         # (1)
class Demo
  var = 2       # (2)
  def method
    var = 3     # (3)
    puts "in method: var = #{var}"
  end
  puts "in class: var = #{var}"
end
puts "at top level: var = #{var}"
Demo.new.method
~~~

Виведе:

~~~
in class: var = 2
at top level: var = 1
in method: var = 3
~~~

(Зверніть увагу, що визначення класу — це виконуваний код: повідомлення
виводиться під час визначення класу).

Блок (`{ ... }` або `do ... end`) майже створює нову область видимості ;-)
Локальні змінні, створені всередині блоку, недоступні поза блоком.
Однак, якщо локальна змінна в блоці має те саме ім’я, що й існуюча локальна
змінна в області виклику, нова змінна не створюється, і ви зможете
звертатися до цієї змінної поза блоком.

~~~
a = 0
1.upto(3) do |i|
  a += i
  b = i*i
end
a  # => 6
# b is not defined here
~~~

Це стає важливим при використанні потоків — кожен потік отримує свою
власну копію змінних, локальних для блоку потоку:

~~~
threads = []

["one", "two"].each do |name|
  threads << Thread.new do
    local_name = name
    a = 0
    3.times do |i|
      Thread.pass
      a += i
      puts "#{local_name}: #{a}"
    end
  end
end

threads.each {|t| t.join }
~~~

Може дати (якщо планувальник перемикає потоки, як підказує `Thread.pass`;
це залежить від ОС і процесора):

~~~
one: 0
two: 0
one: 1
two: 1
one: 3
two: 3
~~~

`while`, `until` і `for` — це керувальні структури, а не блоки, тому
локальні змінні всередині них доступні в зовнішньому середовищі.
`loop`, натомість, є методом і пов’язаний блок вводить нову область видимості.

### Коли локальна змінна стає доступною?

Насправді питання краще сформулювати так: “у який момент Ruby вирішує,
що щось є змінною?” Проблема в тому, що простий вираз `a` може бути або
змінною, або викликом методу без параметрів. Щоб визначити, що це,
Ruby шукає оператори присвоєння. Якщо десь у джерелі до використання `a`
він бачить присвоєння, він вирішує трактувати `a` як змінну; інакше
розглядає це як метод. Як дещо патологічний випадок, розгляньте фрагмент
коду, спочатку надісланий Clemens Hintze:

~~~
def a
  puts "method `a' called"

  99
end

[1, 2].each do |i|
  if i == 2
    puts "a = #{a}"
  else
    a = 1
    puts "a = #{a}"
  end
end
~~~

Виведе:

~~~
a = 1
method `a' called
a = 99
~~~

Під час парсингу Ruby бачить використання `a` у першому `puts` і, оскільки
ще не бачив присвоєння `a`, вважає це викликом методу. Але до другого
`puts` він уже бачив присвоєння, і тому трактує `a` як змінну.

Зверніть увагу: присвоєння не обов’язково має виконатися — Ruby достатньо
просто побачити його. Ця програма не викликає помилку:

~~~
a = 1 if false; a  # => nil
~~~

Ця особливість зі змінними зазвичай не є проблемою. Якщо вона вас
турбує, спробуйте додати присвоєння `a = nil` перед першим доступом до
змінної. Це також має додаткову перевагу — пришвидшує доступ до локальних
змінних, які потім використовуються у циклах.

### Яка область видимості константи?

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

Ви можете напряму звертатися до констант зовнішніх класів і модулів
зсередини вкладених класів і модулів.

Також можна напряму звертатися до констант суперкласів і включених модулів.

Окрім цих випадків, доступ до констант класів і модулів здійснюється через
оператор `::`, `ModuleName::CONST1` або `ClassName::CONST2`.

### Як передаються аргументи?

Фактичний аргумент присвоюється формальному аргументу під час виклику методу.
(Дивіться [присвоєння](#assignment) для деталей семантики присвоєння.)

~~~
def add_one(number)
  number += 1
end

a = 1
add_one(a)  # => 2
a           # => 1
~~~

Оскільки ви передаєте посилання на об’єкти, метод може змінити вміст
змінюваного об’єкта, який йому передали.

~~~
def downer(string)
  string.downcase!
end

a = "HELLO"  # => "HELLO"
downer(a)    # => "hello"
a            # => "hello"
~~~

Еквівалента семантиці pass-by-reference інших мов немає.

### Чи впливає присвоєння формальному аргументу на фактичний аргумент?

Формальний аргумент — це локальна змінна. Усередині методу присвоєння
формальному аргументу просто змінює посилання на інший об’єкт.

### Що відбувається, коли я викликаю метод через формальний аргумент?

Усі змінні Ruby (включно з аргументами методів) діють як посилання на
об’єкти. Ви можете викликати методи цих об’єктів, щоб отримувати або
змінювати стан об’єкта і змушувати об’єкт щось робити. Це можна робити
з об’єктами, переданими в методи. Будьте обережні з цим, адже такі
побічні ефекти можуть ускладнювати розуміння програм.

### Що означає `*`, додана перед аргументом?

Якщо використовується у списку формальних параметрів, зірочка дозволяє
передати довільну кількість аргументів у метод, збираючи їх у масив і
присвоюючи цей масив параметру зі зірочкою.

~~~
def foo(prefix, *all)
  all.each do |element|
    puts "#{prefix}#{element}"
  end
end

foo("val = ", 1, 2, 3)
~~~

Виведе:

~~~
val = 1
val = 2
val = 3
~~~

Коли `*` використовується у виклику методу, вона розгортає масив,
передаючи його елементи як аргументи.

~~~
a = [1, 2, 3]
foo(*a)
~~~

Ви можете ставити `*` перед останнім аргументом у:

1. Лівій частині множинного присвоєння.
2. Правій частині множинного присвоєння.
3. Визначенні формальних аргументів методу.
4. Фактичних аргументах у виклику методу.
5. У `when`-гілці конструкції `case`.

Наприклад:

~~~
x, *y = [7, 8, 9]
x                  # => 7
y                  # => [8, 9]
x,    = [7, 8, 9]
x                  # => 7
x     = [7, 8, 9]
x                  # => [7, 8, 9]
~~~

### Що означає `&`, додана перед аргументом?

Якщо останній формальний аргумент методу має префікс амперсанда (`&`),
блок після виклику методу буде перетворено на об’єкт `Proc` і присвоєно
формальному параметру.

Якщо останній фактичний аргумент під час виклику методу — це об’єкт `Proc`,
ви можете додати перед його ім’ям амперсанд, щоб перетворити його на блок.
Метод потім може викликати його через `yield`.

~~~
def meth1(&b)
  puts b.call(9)
end

meth1 {|i| i + i }

def meth2
  puts yield(8)
end

square = proc {|i| i * i }

meth2 {|i| i + i }
meth2 &square
~~~

Виведе:

~~~
18
16
64
~~~

### Як задати значення за замовчуванням для формального аргументу?

~~~
def greet(p1="hello", p2="world")
  puts "#{p1} #{p2}"
end

greet
greet("hi")
greet("morning", "mom")
~~~

Виведе:

~~~
hello world
hi world
morning mom
~~~

Значення за замовчуванням (яким може бути довільний вираз) обчислюється
під час виклику методу. Воно обчислюється в області видимості методу.

### Як передавати аргументи в блок?

Формальні параметри блоку розташовуються між вертикальними рисками на
початку блоку:

~~~
proc {|a, b| a <=> b }
~~~

Ці параметри — локальні змінні. Якщо на момент виконання блоку існує
локальна змінна з таким самим ім’ям, вона буде змінена викликом блоку.
Це може бути як добре, так і не дуже.

Зазвичай аргументи передаються в блок через `yield` (або ітератор, що
викликає `yield`), або через метод `Proc.call`.

### Чому мій об’єкт несподівано змінився?

~~~
A = a = b = "abc"
b.concat("d")  # => "abcd"
a              # => "abcd"
A              # => "abcd"
~~~

Змінні тримають посилання на об’єкти. Присвоєння `A = a = b = "abc"`
поміщає посилання на рядок `"abc"` у `A`, `a` і `b`.

Коли ви викликаєте `b.concat("d")`, ви викликаєте метод `concat` на цьому
об’єкті, змінюючи його з `"abc"` на `"abcd"`. Оскільки `a` і `A` також
посилаються на той самий об’єкт, їхні видимі значення також змінюються.

На практиці це менш проблемно, ніж може здаватися.

Крім того, усі об’єкти можна заморозити, захистивши їх від змін.

### Чи змінюється значення константи?

Константа — це змінна, ім’я якої починається з великої літери.
Константи не можна переприсвоювати зсередини методів екземпляра,
але в інших місцях їх можна змінювати за бажанням.
Коли константі присвоюється нове значення, видається попередження.

### Чому не можна завантажити змінні з окремого файлу?

Припустімо, що `file1.rb` містить:

~~~
var1 = 99
~~~

а інший файл завантажує його:

~~~
require_relative "file1"
puts var1
~~~

Виведе:

~~~
prog.rb:2:in `<main>': undefined local variable or method `var1' for main:Object (NameError)
~~~

Виникає помилка, оскільки `load` і `require` зберігають локальні змінні
у окремому анонімному просторі імен, фактично відкидаючи їх. Це зроблено,
щоб захистити ваш код від «забруднення».
