У 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