Строки и символы
Строки в Ruby — мощные и гибкие объекты с сотней встроенных методов. А рядом живут символы — лёгкие неизменяемые «имена», которые часто путают со строками.
Суть: строка (String) — это изменяемая последовательность символов с богатым набором методов; символ (Symbol, пишется :имя) — неизменяемый уникальный идентификатор, который дешевле строки и используется как ключ и как имя метода.
Строка — один из самых используемых типов. В Ruby их можно создавать в одинарных и двойных кавычках, склеивать, резать, искать в них подстроки и преобразовывать десятками способов. Двойные кавычки поддерживают интерполяцию #{} и escape-последовательности вроде \n, одинарные — нет, зато работают чуть быстрее и буквальнее.
s = "Ruby для начинающих"
puts s.length # => 19
puts s.upcase # => RUBY ДЛЯ НАЧИНАЮЩИХ
puts s.split(" ").first # => Ruby
puts s.include?("для") # => true
puts s.gsub("Ruby", "Go") # => Go для начинающих
Разбор: изменяемость строк
В отличие от многих языков, строки в Ruby по умолчанию изменяемы: метод upcase! с восклицательным знаком меняет саму строку, а upcase без него возвращает новую копию. Это соглашение «методы с ! опасны / изменяют объект» пронизывает весь язык.
name = "ruby"
name.upcase # => "RUBY", но name всё ещё "ruby"
name.upcase! # name теперь "RUBY" — изменили на месте
puts name # => RUBY
Разбор: зачем нужны символы
Символ :status похож на строку "status", но это другой объект. Ключевое отличие: для каждого уникального символа в программе существует ровно один экземпляр в памяти, и он неизменяем. Поэтому символы идеальны как ключи хэшей и имена — их сравнение мгновенно, а памяти они почти не тратят.
строки символы "name" в строке 1 :name в строке 1 ---+ "name" в строке 2 +--> ОДИН объект :name (могут быть РАЗНЫЕ :name в строке 2 ---+ объекты в памяти) (всегда ОДИН и тот же)
puts :name.object_id == :name.object_id # => true (один объект)
puts "n".object_id == "n".object_id # => false (разные объекты)
user = { name: "Аня", role: :admin } # ключи-символы
puts user[:name] # => Аня
Как работает под капотом
Когда Ruby встречает символ :status, он заносит его в внутреннюю таблицу символов один раз. Повторные упоминания возвращают ссылку на тот же объект. Строки же при каждом литерале (без оптимизаций) могут создаваться заново. Именно поэтому в Ruby 3.4 появилось «строки ведут себя как замороженные по умолчанию» — оптимизация, при которой одинаковые строковые литералы могут переиспользоваться, снижая нагрузку на сборщик мусора.
Частые ошибки
- Смешивать ключи-строки и ключи-символы.
{ "name" => "Аня" }[:name]вернётnil: строка и символ — разные ключи. - Забывать про разницу версий с
!.arr.sortвозвращает новый массив,arr.sort!меняет исходный. Перепутали — потеряли данные. - Конкатенация в цикле. Тысячи
+=создают много мусорных строк; для сборки текста используйте массив иjoin.
Best practices
- Используйте символы для фиксированных «меток»: статусов, ролей, ключей хэшей.
- Предпочитайте интерполяцию
"Привет, #{name}"конкатенации"Привет, " + name— она читабельнее и не падает на не-строках. - Добавляйте
# frozen_string_literal: trueв начало файлов — это включает заморозку строк и ускоряет программу.
Глубже: кодировки и заморозка строк
Ещё две темы вокруг строк, которые отличают новичка от уверенного рубиста. Первая — кодировки. Современный Ruby по умолчанию работает в UTF-8, и метод length честно считает символы, а не байты: для строки с кириллицей или эмодзи вы получите число букв, а не объём памяти. Если же нужны именно байты, есть bytesize. Это избавляет от целого класса ошибок, мучивших программистов в эпоху до повсеместного Unicode. Вторая тема — заморозка строк. Магический комментарий # frozen_string_literal: true в начале файла делает все строковые литералы неизменяемыми. Это даёт прирост производительности (одинаковые литералы переиспользуются, а не создаются заново) и защищает от случайных мутаций общих строк. В Ruby 3.4 язык сделал шаг к тому, чтобы такое поведение стало стандартным: мутация литерала без магического комментария теперь выдаёт предупреждение. Привыкайте добавлять этот комментарий в каждый файл — это бесплатная оптимизация и хороший тон.
Итог. Строки изменяемы и богаты методами, версии с ! меняют объект на месте. Символы — лёгкие неизменяемые идентификаторы, единственные в своём роде; берите их для ключей и меток.