[Ruby] Чим відрізняються змінні, що починаються з @, @@ та $?
Дисклеймер

Інформація на сайті tseivo.com є суб'єктивною та відображає особисті погляди та досвід авторів та авторок блогів.

Використовуйте цей ресурс як одне з декількох джерел інформації під час своїх досліджень та прийняття рішень. Завжди застосовуйте критичне мислення. Людина сама несе відповідальність за свої рішення та дії.

Обкладинка нотатки: [Ruby] Чим відрізняються змінні, що починаються з @, @@ та $?

[Ruby] Чим відрізняються змінні, що починаються з @, @@ та $?

У Ruby змінні, що починаються з @, @@ та $, мають різні рівні видимості та використання (скоуп). Розглянемо приклади та спробуємо максимально просто пояснити відмінності.

@ або @instance_variable

Змінні, що починаються з @, є змінними екземпляра. Вони належать конкретному об'єкту (екземпляру класу) і є доступними тільки в межах цього об'єкта. Кожен екземпляр класу має свої власні змінні екземпляра. Перевіримо:
class Example
  def initialize(value)
    @instance_variable = value
  end

  def show
    @instance_variable
  end
end

obj1 = Example.new(10)
obj2 = Example.new(20)

puts obj1.show  # Виведе 10
puts obj2.show  # Виведе 20
Метод ініціалізації об'єкта приймає значення і встановлює його у змінну екземпляра (коли ми викликаємо метод show на об'єкті obj1 спочатку виконується ініціалізація а потім сам метод). Метод show повертає значення змінної екземпляра.
Тобто змінна яка задається за допомогою символу @ дає можливість шейрити значення серед методів класу в контексті об'єкту. Кожен новий об'єкт, наприклад obj2 буде мати своє значення у змінній @instance_variable.

@@ або @@class_variable

Змінні, що починаються з @@, є змінними класу. Вони спільні для всіх екземплярів класу. Якщо одна з змінних класу змінюється в одному екземплярі класу, ця зміна буде видима в усіх інших екземплярах цього класу.
Простий приклад:
class Example
  @@class_variable = 0

  def self.increment
    @@class_variable += 1
  end

  def self.show
    @@class_variable
  end
end

Example.increment
Example.increment

puts Example.show  # Виведе 2
Тобто змінні класу впливають на всі об'єкти цього класу. Іноді це доволі небезпечно і треба бути дуже уважними, щоб не наробити шкоди вплинувши на всі об'єкти.

$ або $global_variable

Змінні, що починаються з $, є глобальними змінними. Вони доступні з будь-якої частини програми, незалежно від області видимості. Використання глобальних змінних може ускладнювати відстеження стану програми, тому їх варто уникати, якщо це можливо.
Приклад:
$global_variable = 10

def show_global
  $global_variable
end

puts show_global  # Виведе 10
Приклад не дуже наочний, але технічно - ця глобальна змінна може бути змінена та використана будь-де в програмі.

Коротко підсумовуючи

  • @instance_variable: змінна екземпляра, унікальна для кожного об'єкта.
  • @@class_variable: змінна класу, спільна для всіх екземплярів класу.
  • $global_variable: глобальна змінна, доступна з будь-якої частини програми.
Ну й вчимось писати тести - завжди можна перевірити якісь твердження за допомогою тестів.
test.rb
require 'rspec'

class Example
  @@class_variable = 0
  $global_variable = 0

  def initialize(value)
    @instance_variable = value
  end

  def increment_class_variable
    @@class_variable += 1
  end

  def increment_global_variable
    $global_variable += 1
  end

  def instance_variable
    @instance_variable
  end

  def self.class_variable
    @@class_variable
  end

  def self.global_variable
    $global_variable
  end
end

RSpec.describe 'Різні типи змінних' do
  before do
    @example1 = Example.new(1)
    @example2 = Example.new(2)
  end

  context 'змінні екземпляра' do
    it 'унікальні для кожного об\'єкта' do
      expect(@example1.instance_variable).to eq(1)
      expect(@example2.instance_variable).to eq(2)
    end
  end

  context 'змінні класу' do
    it 'спільні для всіх екземплярів класу' do
      @example1.increment_class_variable
      @example2.increment_class_variable
      expect(Example.class_variable).to eq(2)
    end
  end

  context 'глобальні змінні' do
    it 'доступні з будь-якої частини програми' do
      @example1.increment_global_variable
      @example2.increment_global_variable
      expect(Example.global_variable).to eq(2)
    end
  end
end
rspec test.rb ...
Finished in 0.01932 seconds (files took 0.28601 seconds to load)
3 examples, 0 failures

🙌 Підтримати блог @memecode

Ви можете поширити цей допис у соцмережах, чим допоможете платформі цейво розвиватись (* ^ ω ^)

📝 Більше публікацій: