Що робить коментар "Заморожений_три_літераль: правда"?


226

Це rspecbinstub в моєму каталозі проектів.

#!/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

Відповіді:


314

# 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

Ви також можете заморозити змінну (незаморожену) рядок з унарною -.


24
Важливо зауважити, що стосується заморожування рядків, це те, що це покращує продуктивність програми . Дивіться також тут
Андрес Еренпрейс

2
@ dave-schweisguth Чи не слід очікувати, що ми -"foo"будемо таким самим "foo".freeze? Коли я перевіряю, (-"foo").__id__я щоразу отримую інше значення, але "foo".freeze.__id__щоразу однакове. Будь-які ідеї?
lilole

Цікаво, чи ця проблема є проблемою, вона, здається, називається лише з одинарним мінусом. github.com/ruby/ruby/blob/trunk/string.c#L2572
lilole

2
-призначений для дедуплікації рядка для збереження пам'яті, крім повернення замороженої рядка.
ерегон

9
Хоча ви все ще можете використовувати чарівний коментар, Матц офіційно вирішив не робити всіх рядкових літералів незмінними за замовчуванням у Ruby 3: bugs.ruby-lang.org/isissue/11473#note-53
Костянтин Тихонов

43

Це покращує продуктивність програми, не виділяючи новий простір для тієї ж строки, тим самим заощаджуючи час на завдання по збору сміття. Як? коли ви заморожуєте рядковий літерал (об’єкт рядка), ви говорите Рубі, щоб не дозволяв жодній із ваших програм змінювати рядковий літерал (об'єкт).

Деякі очевидні спостереження, які слід пам’ятати.

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'  #=> `<main>': can't modify frozen String (FrozenError)

puts name      

Завжди можна дізнатися більше і бути гнучкими:


Це більш інтуїтивна відповідь.
Джин Лім

20

В Ruby 3.0. Мац (творець Рубі) вирішив замовити всі лінійні String за замовчуванням.

Ви можете використовувати в Ruby 2.x. Просто додайте цей коментар у перший рядок своїх файлів.

# frozen_string_literal: true

Наведений коментар у верхній частині файлу змінює семантику статичних рядкових літералів у файлі. Літерали статичного рядка будуть заморожені і завжди повертають той самий об'єкт. (Семантика динамічних рядкових літералів не змінена.)

Цей спосіб має наступні переваги:

Немає потворного f-суфікса. Немає синтаксичної помилки на старшому Ruby. Нам потрібен лише рядок для кожного файлу.

Будь ласка, прочитайте цю тему для отримання додаткової інформації.

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


На жаль, цей коментар не працює для рядків у масивах, тому їх все одно потрібно чітко заморозити
заморозити

3
На жаль, цього не буде в рубінах 3 bugs.ruby-lang.org/isissue/11473#note-53
zhisme
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.