Что делает комментарий "frozen_string_literal: true"?

Это rspec binstub в моем каталоге проектов.

#!/usr/bin/env ruby
begin
  load File.expand_path("../spring", __FILE__)
rescue LoadError
end
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'rspec' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
  Pathname.new(__FILE__).realpath)

require "rubygems"
require "bundler/setup"

load Gem.bin_path("rspec-core", "rspec")

Что это должно сделать?

# frozen_string_literal: true

2 ответа

Решение

# frozen_string_literal: true это магический комментарий, впервые поддерживаемый в Ruby 2.3, который говорит Ruby, что все строковые литералы в файле неявно заморожены, как если бы #freeze был вызван на каждого из них. То есть, если строковый литерал определен в файле с этим комментарием, и вы вызываете метод для этой строки, который изменяет его, например, <<, ты получишь RuntimeError: can't modify frozen String,

Комментарий должен быть в первой строке файла.

В Ruby 2.3 этот магический комментарий можно использовать для подготовки к фиксированным строковым литералам, которые по умолчанию используются в Ruby 3.

В Ruby 2.3 запустить с --enable=frozen-string-literal флаг, а в Ruby 3 строковые литералы заморожены во всех файлах. Вы можете переопределить глобальные настройки с помощью # frozen_string_literal: false,

Если вы хотите, чтобы строковый литерал был изменяемым независимо от глобальных или файловых настроек, вы можете использовать префикс с одинарным + оператор (будьте осторожны с приоритетом оператора) или вызов .dup в теме:

# frozen_string_literal: true
"".frozen?
=> true
(+"").frozen?
=> false
"".dup.frozen?
=> false

Вы также можете заморозить изменяемую (незамерзшую) строку с помощью одинарного -,

Это повышает производительность приложения, не выделяя новое пространство для той же строки, тем самым экономя время на сборку мусора. Как? когда вы замораживаете строковый литерал (строковый объект), вы говорите Ruby, чтобы ни одна из ваших программ не изменяла строковый литерал (объект).

Несколько очевидных наблюдений, которые нужно иметь в виду.

1. Замораживая строковые литералы, вы не выделяете для этого новое пространство памяти.

Пример:

Без магического комментария выделяется новое место для той же строки (обратите внимание на разные идентификаторы объекта)

def hello_id
  a = 'hello'
  a.object_id
end

puts hello_id   #=> 70244568358640
puts hello_id   #=> 70244568358500

С магическим комментарием, рубин выделяет место только один раз

# frozen_string_literal: true

def hello_id
  a = 'hello'
  a.object_id
end

puts hello_id   #=> 70244568358640
puts hello_id   #=> 70244568358640

2. Замораживая строковые литералы, ваша программа вызовет исключение при попытке изменить строковый литерал.

Пример:

Без магического комментария вы можете изменить строковые литералы.

name = 'Johny'
name << ' Cash'

puts name     #=> Johny Cash

С волшебным комментарием, будет возникать исключение, когда вы изменяете строковые литералы

# frozen_string_literal: true

name = 'john'
name << ' cash'

puts name      #=> `<main>': can't modify frozen String (FrozenError)

Всегда есть чему поучиться и быть гибким:

В Ruby 3.0. Matz (создатель Ruby) решил сделать все строковые литералы замороженными по умолчанию.

Вы можете использовать в Ruby 2.x. Просто добавьте этот комментарий в первую строку ваших файлов.

# frozen_string_literal: true

Приведенный выше комментарий в верхней части файла меняет семантику статических строковых литералов в файле. Статические строковые литералы будут заморожены и всегда будут возвращать один и тот же объект. (Семантика динамических строковых литералов не изменяется.)

Этот способ имеет следующие преимущества:

Нет уродливого f-суффикса. Нет ошибки синтаксиса на старых Ruby. Нам нужна только строка для каждого файла.

Пожалуйста, прочитайте эту тему для получения дополнительной информации.

https://bugs.ruby-lang.org/issues/8976

Другие вопросы по тегам