Cosa fa il commento "frozen_string_literal: true"?


226

Questo è il rspecbinstub nella directory del mio progetto.

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

Cosa si intende fare?

# frozen_string_literal: true

Risposte:


314

# frozen_string_literal: trueè un commento magico, supportato per la prima volta in Ruby 2.3, che dice a Ruby che tutti i letterali stringa nel file sono implicitamente congelati, come se #freezefossero stati chiamati su ciascuno di essi. Cioè, se una stringa letterale è definita in un file con questo commento e si chiama un metodo su quella stringa che lo modifica, come ad esempio <<, si otterrà RuntimeError: can't modify frozen String.

Il commento deve essere sulla prima riga del file.

In Ruby 2.3, puoi usare questo commento magico per prepararti per i letterali di stringhe congelati come impostazione predefinita in Ruby 3 .

In Ruby 2.3 corri con la --enable=frozen-string-literalbandiera, e in Ruby 3, i letterali delle stringhe sono congelati in tutti i file. È possibile ignorare l'impostazione globale con # frozen_string_literal: false.

Se vuoi che una stringa letterale sia mutabile indipendentemente dall'impostazione globale o per file, puoi prefissarla con l' +operatore unario (facendo attenzione alla precedenza dell'operatore) o chiamarla .dup:

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

Puoi anche congelare una stringa mutabile (non congelata) con unario -.


24
La cosa importante da notare per quanto riguarda il congelamento delle stringhe è che migliora le prestazioni dell'app . Vedi anche qui
Andres Ehrenpreis,

2
@ dave-schweisguth Non dovremmo aspettarci -"foo"di essere lo stesso di "foo".freeze? Quando controllo (-"foo").__id__ottengo un valore diverso ogni volta, ma "foo".freeze.__id__ogni volta è uguale. Qualche idea?
lilole,

Mi chiedo se questa funzione sia il problema, sembra essere chiamata solo con il meno unario. github.com/ruby/ruby/blob/trunk/string.c#L2572
lilole

2
-serve per deduplicare la stringa per risparmiare memoria, oltre a restituire una stringa congelata.
eregon,

9
Mentre puoi ancora usare il commento magico, Matz ha deciso ufficialmente di non rendere immutabili tutti i letterali stringa per impostazione predefinita in Ruby 3: bugs.ruby-lang.org/issues/11473#note-53
Konstantin Tikhonov,

44

Migliora le prestazioni dell'applicazione non allocando nuovo spazio per la stessa stringa, risparmiando così tempo per le faccende della garbage collection. Come? quando congeli una stringa letterale (oggetto stringa), stai dicendo a Ruby di non permettere a nessuno dei tuoi programmi di modificare la stringa letterale (oggetto).

Alcune ovvie osservazioni da tenere a mente.

1. Congelando i letterali delle stringhe, non stai allocando nuovo spazio di memoria per esso.

Esempio:

Senza commento magico alloca nuovo spazio per la stessa stringa (osserva i diversi ID oggetto stampati)

def hello_id
  a = 'hello'
  a.object_id
end

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

Con un commento magico , il rubino alloca lo spazio solo una volta

# frozen_string_literal: true

def hello_id
  a = 'hello'
  a.object_id
end

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

2. Congelando i valori letterali di stringa, il programma genererà un'eccezione quando si tenta di modificare il valore letterale di stringa.

Esempio:

Senza commenti magici , puoi modificare i valori letterali delle stringhe.

name = 'Johny'
name << ' Cash'

puts name     #=> Johny Cash

Con il commento magico , verrà sollevata un'eccezione quando si modificano valori letterali di stringa

# frozen_string_literal: true

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

puts name      

C'è sempre altro da imparare ed essere flessibile:


Questa è una risposta più intuitiva.
Jin Lim

20

In Ruby 3.0. Matz (creatore di Ruby) ha deciso di rendere tutti i letterali String congelati per impostazione predefinita.

È possibile utilizzare in Ruby 2.x. Aggiungi questo commento nella prima riga dei tuoi file.

# frozen_string_literal: true

Il commento sopra nella parte superiore di un file modifica la semantica dei valori letterali delle stringhe statiche nel file. I valori letterali delle stringhe statiche verranno congelati e restituiranno sempre lo stesso oggetto. (La semantica dei valori letterali stringa dinamici non viene modificata.)

In questo modo ha i seguenti vantaggi:

Nessun brutto suffisso f. Nessun errore di sintassi su Ruby precedente. Abbiamo solo bisogno di una riga per ogni file.

Per favore, leggi questo argomento per maggiori informazioni.

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


Sfortunatamente questo commento non funziona per le stringhe negli array, quindi devono ancora essere congelati esplicitamente
ToTenMilan,

3
Purtroppo questo non sarà in ruby ​​3 bugs.ruby-lang.org/issues/11473#note-53
zhisme,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.