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


## Класи та модулі

### Чи можна повторно визначати клас?

Клас можна визначати повторно. Кожне визначення додається до
попереднього. Якщо метод перевизначено, попередній перевизначається
і втрачається.

### Чи існують змінні класу?

Так. Змінна з двома знаками `@` (`@@`) — це змінна класу, доступна як у
методах екземпляра, так і в методах класу.

~~~
class Entity

  @@instances = 0

  def initialize
    @@instances += 1
    @number = @@instances
  end

  def who_am_i
   "I'm #{@number} of #{@@instances}"
  end

  def self.total
    @@instances
  end
end

entities = Array.new(9) { Entity.new }

entities[6].who_am_i  # => "I'm 7 of 9"
Entity.total          # => 9
~~~

Однак, найімовірніше, варто використовувати _змінні екземпляра класу_.

### Що таке змінна екземпляра класу?

Ось приклад із попереднього розділу, переписаний із використанням змінної
екземпляра класу:

~~~
class Entity

  @instances = 0

  class << self
    attr_accessor :instances  # provide class methods for reading/writing
  end

  def initialize
    self.class.instances += 1
    @number = self.class.instances
  end

  def who_am_i
   "I'm #{@number} of #{self.class.instances}"
  end

  def self.total
    @instances
  end
end

entities = Array.new(9) { Entity.new }

entities[6].who_am_i  # => "I'm 7 of 9"
Entity.instances      # => 9
Entity.total          # => 9
~~~

Тут `@instances` — це _змінна екземпляра_ класу. Вона не належить
екземпляру класу `Entity`, а належить об’єкту класу `Entity`, який є
екземпляром класу `Class`.

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

### У чому різниця між змінними класу та змінними екземпляра класу?

Головна різниця — у поведінці щодо наслідування: змінні класу спільні для
класу та всіх його підкласів, тоді як змінні екземпляра класу належать
лише одному конкретному класу.

Змінні класу певною мірою можна розглядати як глобальні змінні в контексті
ієрархії наслідування, з усіма проблемами, притаманними глобальним змінним.
Наприклад, змінна класу може (випадково) бути переприсвоєна будь-яким із
підкласів, що вплине на всі інші класи:

~~~
class Woof

  @@sound = "woof"

  def self.sound
    @@sound
  end
end

Woof.sound  # => "woof"

class LoudWoof < Woof
  @@sound = "WOOF"
end

LoudWoof.sound  # => "WOOF"
Woof.sound      # => "WOOF" (!)
~~~

Або клас-предка можуть згодом повторно відкрити й змінити, що може мати
несподівані наслідки:

~~~
class Foo

  @@var = "foo"

  def self.var
    @@var
  end
end

Foo.var  # => "foo" (as expected)

class Object
  @@var = "object"
end

Foo.var  # => "object" (!)
~~~

Тож якщо ви точно не знаєте, що робите, і вам справді не потрібна така
поведінка, краще використовуйте змінні екземпляра класу.

### Чи має Ruby методи класу?
{: #class-method}

Singleton-метод об’єкта класу називається методом класу.
(Насправді метод класу визначається в метакласі, але це здебільшого
прозоро). Інакше кажучи, метод класу — це метод, отримувачем якого є клас.

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

Створімо singleton-метод класу `Foo`:

~~~
class Foo
  def self.test
    "this is foo"
  end
end

# It is invoked this way.

Foo.test  # => "this is foo"
~~~

У цьому прикладі `Foo.test` — метод класу.

Методи екземпляра, визначені в класі `Class`, можна використовувати як
методи класу для кожного(!) класу.

### Що таке singleton-клас?

Singleton-клас — це анонімний клас, створений шляхом наслідування класу,
пов’язаного з конкретним об’єктом. Singleton-класи — ще один спосіб
розширити функціональність, пов’язану лише з одним об’єктом.

Візьмімо скромний `Foo`:

~~~
class Foo
  def hello
    "hello"
  end
end

foo = Foo.new
foo.hello  # => "hello"
~~~

А тепер уявімо, що потрібно додати функціональність рівня класу лише для
цього одного екземпляра:

~~~
class << foo
  attr_accessor :name

  def hello
    "hello, I'm #{name}"
  end
end

foo.name = "Tom"
foo.hello         # => "hello, I'm Tom"
Foo.new.hello     # => "hello"
~~~

Ми налаштували `foo`, не змінюючи характеристики `Foo`.

### Що таке функція модуля?

<div class="not-prose bg-ruby-100 dark:bg-ruby-800 rounded-lg p-8 my-6">
  <div class="flex items-start gap-3">
    <svg class="w-6 h-6 text-ruby-700 dark:text-ruby-200 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
      <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd"/>
    </svg>
    <p class="text-sm text-ruby-700 dark:text-ruby-200 italic">
      This section or parts of it might be out-dated or in need of confirmation.
    </p>
  </div>
</div>


Функція модуля — це приватний singleton-метод, визначений у модулі.
По суті, це схоже на [метод класу](#class-method), оскільки його можна
викликати у вигляді `Module.method`:

~~~
Math.sqrt(2)  # => 1.414213562
~~~

Проте, оскільки модулі можна домішувати до класів, функції модуля можна
використовувати і без префікса (саме так функції `Kernel` стають
доступними об’єктам):

~~~
include Math
sqrt(2)  # => 1.414213562
~~~

Використайте `module_function`, щоб зробити метод функцією модуля.

~~~
module Test
  def thing
    # ...
  end
  module_function :thing
end
~~~

### У чому різниця між класом і модулем?

Модулі — це колекції методів і констант. Вони не можуть створювати
екземпляри. Класи можуть створювати екземпляри (об’єкти) і мають стан на
рівні екземпляра (змінні екземпляра).

Модулі можна домішувати до класів і інших модулів. Константи й методи
домішаного модуля змішуються з власними константами й методами класу,
розширюючи його функціональність. Натомість класи не можна домішувати
ні до чого.

Клас може успадковувати інший клас, але не модуль.

Модуль не може наслідувати нічого.

### Чи можна успадковувати модулі?

Ні. Однак модуль можна включити до класу або іншого модуля, щоб імітувати
множинне наслідування (механізм mixin).

Це не створює підклас (для цього потрібне наслідування), але створює
зв’язок `is_a?` між класом і модулем.

### Наведіть приклад mixin

Модуль `Comparable` надає різноманітні оператори порівняння
(`<`, `<=`, `==`, `>=`, `>`, `between?`). Він визначає їх через виклики
загального методу порівняння `<=>`. Однак сам `<=>` він не визначає.

Припустімо, ви хочете створити клас, у якому порівняння ґрунтуються на
кількості ніг тварини:

~~~
class Animal
  include Comparable

  attr_reader :legs

  def initialize(name, legs)
    @name, @legs = name, legs
  end

  def <=>(other)
    legs <=> other.legs
  end

  def inspect
    @name
  end
end

c = Animal.new("cat", 4)
s = Animal.new("snake", 0)
p = Animal.new("parrot", 2)

c < s             # => false
s < c             # => true
p >= s            # => true
p.between?(s, c)  # => true
[p, s, c].sort    # => [snake, parrot, cat]
~~~

Все, що потрібно `Animal`, — визначити власну семантику оператора `<=>`
і домішати модуль `Comparable`. Методи `Comparable` стають
невідрізненними від методів `Animal`, і ваш клас раптово отримує нову
функціональність. А оскільки той самий модуль `Comparable` використовують
багато класів, ваш новий клас матиме узгоджену й добре зрозумілу семантику.

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

Метод класу можна визначити всередині визначення класу, а також на
верхньому рівні.

~~~
class Demo
  def self.class_method
  end
end

def Demo.another_class_method
end
~~~

Між ними є лише одна суттєва різниця. У визначенні класу можна звертатися
до констант класу безпосередньо, оскільки вони в області видимості.
На верхньому рівні потрібно використовувати нотацію `Class::CONST`.

### У чому різниця між `include` і `extend`?

<div class="not-prose bg-ruby-100 dark:bg-ruby-800 rounded-lg p-8 my-6">
  <div class="flex items-start gap-3">
    <svg class="w-6 h-6 text-ruby-700 dark:text-ruby-200 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
      <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd"/>
    </svg>
    <p class="text-sm text-ruby-700 dark:text-ruby-200 italic">
      This section or parts of it might be out-dated or in need of confirmation.
    </p>
  </div>
</div>


`include` домішує модуль до класу або іншого модуля. Методи з цього
модуля викликаються у функціональному стилі (без отримувача).

`extend` використовується, щоб включити модуль в об’єкт (екземпляр).
Методи модуля стають методами об’єкта.

### Що означає `self`?

`self` — це поточний отримувач виконання, об’єкт, до якого
застосовується метод. Виклик методу у функціональному стилі
передбачає `self` як отримувача.
