Обкладинка нотатки: В чому різниця між immediate value та reference у Ruby?

В чому різниця між immediate value та reference у Ruby?

Зміст дописунатисність на посилання, щоб перейти до потрібного місця
Спочатку треба розібратись що таке таке immediate value та reference у Ruby.
Безпосереднє значення (immediate value) в мові програмування - це значення, яке зберігається напряму в змінній або об'єкті, без посилання на іншу область пам'яті. Це може бути число, символ, true, false або nil. Наприклад, коли ви присвоюєте змінній число, це безпосереднє значення.
Посилання (reference) вказує на область пам'яті, де зберігається об'єкт. Об'єкти, які зазвичай зберігаються за допомогою посилань, включають строки, масиви, хеші та об'єкти класів. Коли ви працюєте з об'єктом за допомогою посилання, ви фактично працюєте з областю пам'яті, де зберігається сам об'єкт.
У дописі про призначення змінної змінній у ruby ми розглянули концепцію посилання (reference). Але не розглянули безпосередні значення.

Immediate values у Ruby

Immediate value - це значення, яке зберігається безпосередньо в змінній, а не через посилання на об'єкт. Але є один момент, який особисто мене трохи збив з пантелику. У Ruby навіть для immediate value змінні мають object_id, але вони вказують на конкретне місце в пам'яті, де зберігається значення, а не на об'єкт, як у випадку посилань. Тобто, у випадку immediate value object_id не вказує на об'єкт в пам'яті, а просто ідентифікує конкретне значення, яке зберігається безпосередньо в змінній. Так, в Ruby не все є об'єктом.
Цитата з apidock:
object_id() public

Returns an integer identifier for obj.

The same number will be returned on all calls to object_id for a given object, and no two active objects will share an id.

Note: that some objects of builtin classes are reused for optimization. This is the case for immediate values and frozen string literals.

Immediate values are not passed by reference but are passed by value: nil, true, false, Fixnums, Symbols, and some Floats.
Ці значення зберігаються безпосередньо в змінних та не можуть бути змінені через посилання на об'єкт. Вони є найбільш ефективним способом зберігання даних у пам'яті, оскільки не потребують виділення пам'яті для об'єкта. Зроблено це задля оптимізації пам'яті. Немає сенсу створювати нові об'єкти під кожен nil. Тож давайте трохи пограємось з IRB.
Строка - це об'єкт.
a = 'hehe'
b = 'hehe'

a == b
=> true # Строки й справді однакові

a.object_id == b.object_id
=> false # Ми маємо два різних об'єкти для зберігання однакового контенту 
Символи - безпосередні значення
a = :test
=> :test
b = :test
=> :test
a.object_id == b.object_id
=> true # Ми маємо одне значення в пам'яті, та дві змінні, які вказують на нього
Теж саме з true, false та nil
a = true
b = true
a.object_id == b.object_id
=> true

a = false
b = false
a.object_id == b.object_id
=> true

a = nil
b = nil
a.object_id == b.object_id
=> true
Ruby резервує певні object IDs для цих об'єктів immediate values, оскільки кожна змінна, якій призначено immediate value  - посилається на те саме місце в пам'яті. Перевіримо:
true.object_id
=> 20
false.object_id
=> 0
nil.object_id
=> 4

a = true
=> true

b = false
=> false

c = nil
=> nil

a.object_id
=> 20

b.object_id
=> 0

c.object_id
=> 4
А краще - напишемо rspec:
require 'rspec'

describe "Immediate values та references в Ruby" do
  it "демонструє immediate values vs references" do
    # Immediate values
    a = 5
    b = a
    expect(a.object_id).to eq(b.object_id)

    # Reference
    a = [1, 2, 3]
    b = a
    expect(a.object_id).to eq(b.object_id)
  end

  it "демонструє object_id для immediate values" do
    # True
    a = true
    b = true
    expect(a.object_id).to eq(b.object_id)

    # False
    a = false
    b = false
    expect(a.object_id).to eq(b.object_id)

    # Nil
    a = nil
    b = nil
    expect(a.object_id).to eq(b.object_id)
  end

  it "демонструє object_id для symbols" do
    a = :test
    b = :test
    expect(a.object_id).to eq(b.object_id)
  end

  it "демонструє object_id для frozen literals" do
    a = 'test'.freeze
    b = 'test'.freeze
    expect(a.object_id).to eq(b.object_id)
  end

  it "демонструє статичний object_id для true, false, nil" do
    expect(true.object_id).to eq(20)
    expect(false.object_id).to eq(0)
    expect(nil.object_id).to eq(4)
  end
end
Finished in 0.01952 seconds (files took 0.27884 seconds to load)

5 examples, 0 failures
Сподіваюсь комусь ця інфа допоможе трохи розібратись з  immediate value та reference у Ruby. 

🔗 Цитувати допис: "В чому різниця між immediate value та reference у Ruby?"

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

Розгорнути деталі


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

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

📝 Більше публікацій:
Обкладинка нотатки: Що таке "розповзання скоупу" (Scope Creep / Скоуп кріп)?
Обкладинка нотатки: Що означає "Нативний"?
Обкладинка нотатки: Як працює 'rails console --sandbox'?
Обкладинка нотатки: Для чого потрібна база даних CVE (Common Vulnerabilities and Exposures)?
Обкладинка нотатки: Чи створює Ruby нову копію об’єкта при присвоєнні змінної змінній?
Обкладинка нотатки: Чому Ruby код повертає nil після виконання puts?
Обкладинка нотатки: Яка різниця між nil і false в Ruby?
Обкладинка нотатки: Чому порожній рядок (string) у Ruby не є false?
Обкладинка нотатки: Область видимості локальної змінної в Ruby
Обкладинка нотатки: Чим відрізняється int та bigint в Ruby? Мінімальні та максимальні значення.
Обкладинка нотатки: Що означає помилка 'is out of range' в Ruby on Rails? Range Error - Integer with limit 4 bytes
Дисклеймер

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

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