Зміст дописунатисність на посилання, щоб перейти до потрібного місця
У 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