Символи проти рядків у Ruby

У Ruby символи (:symbol) та рядки ("string") використовуються для представлення тексту, але вони поводяться по-різному щодо продуктивності, змінності та використання пам'яті. Ось розбір:

1. Непорушність та Унікальність

  • Символи (:symbol) непорушні та унікальні. Кожне виникнення того самого символу посилається на один і той самий об'єкт.
  • Рядки ("string") змінні, і різні екземпляри з однаковим значенням є різними об'єктами.
:hello.object_id == :hello.object_id # => true (один і той самий об'єкт)  
"hello".object_id == "hello".object_id # => false (різні об'єкти)

2. Продуктивність та Ефективність використання пам'яті

  • Символи більш ефективні по пам'яті, оскільки вони зберігаються лише один раз у таблиці символів Ruby і повторно використовуються.
  • Рядки споживають більше пам'яті, оскільки кожен раз при створенні рядка генерується новий об'єкт.
100_000.times { :symbol } # Використовує той самий об'єкт багато разів  
100_000.times { "string" } # Створює новий об'єкт рядка щоразу

3. Продуктивність пошуку в хешах

  • Символи є швидшими як ключі в хешах, оскільки вони непорушні та порівнюються за ідентичністю (object_id).
  • Рядки є повільнішими, оскільки для їх порівняння потрібно перевіряти вміст (== перевіряє кожен символ).
require 'benchmark'  

n = 100_000  
hash_with_symbols = { hello: "world" }  
hash_with_strings = { "hello" => "world" }  

Benchmark.bm do |x|  
 x.report("symbol key: ") { n.times { hash_with_symbols[:hello] } }  
 x.report("string key: ") { n.times { hash_with_strings["hello"] } }  
end🔹 Example: Hash key lookup speed

4. Змінність

  • Символи непорушні — ви не можете змінити їхній вміст.
  • Рядки змінні — ви можете змінити їхній вміст безпосередньо.
str = "hello"  
str.upcase! # змінює рядок на місці, тепер str = "HELLO"  

sym = :hello  
sym.upcase! # NoMethodError: undefined method `upcase!' for :hello

4. Використання

  • Використовуйте символи для ідентифікаторів, ключів чи констант (наприклад, ключі хешу, імена методів).
  • Використовуйте рядки, коли потрібно змінювати текст (наприклад, введення користувача, вміст файлів).
user = { name: "Alice", age: 25 }  
user[:name] # Символи ідеально підходять для ключів хешу

5. Символи vs Рядки в хешах

  • Символи зазвичай використовуються як ключі в хешах, оскільки вони ефективніші.
  • Rails надає HashWithIndifferentAccess, що дозволяє використовувати як :symbol, так і "string" як ключі, працюючи взаємозамінно.

6. Збір сміття

  • Символи не збирались сміттям до Ruby 2.2, що означало, що надмірне створення динамічних символів (:"some#{value}") могло призвести до накопичення пам'яті.
  • Починаючи з Ruby 2.2+, символи збираються сміттям, якщо вони були динамічно створені.

Висновок

  • Використовуйте символи, коли ідентифікатори залишаються сталими (наприклад, ключі хешу, імена методів).
  • Використовуйте рядки, коли працюєте з динамічним або текстом, створеним користувачем.

Перекладено з: Symbols vs. Strings in Ruby