À quoi sert le commentaire «freez_string_literal: true»?

226

Ceci est le rspecbinstub dans mon répertoire de projet.

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

Qu'est-ce que cela vise à faire?

# frozen_string_literal: true
messanjah
la source

Réponses:

314

# frozen_string_literal: trueest un commentaire magique, pris en charge pour la première fois dans Ruby 2.3, qui indique à Ruby que tous les littéraux de chaîne dans le fichier sont implicitement figés, comme s'ils #freezeavaient été appelés sur chacun d'eux. Autrement dit, si un littéral de chaîne est défini dans un fichier avec ce commentaire, et que vous appelez une méthode sur cette chaîne qui la modifie, par exemple <<, vous obtiendrez RuntimeError: can't modify frozen String.

Le commentaire doit figurer sur la première ligne du fichier.

Dans Ruby 2.3, vous pouvez utiliser ce commentaire magique pour vous préparer à ce que les littéraux de chaîne figés soient la valeur par défaut dans Ruby 3 .

Dans Ruby 2.3 exécuté avec l' --enable=frozen-string-literalindicateur, et dans Ruby 3, les littéraux de chaîne sont figés dans tous les fichiers. Vous pouvez remplacer le paramètre global avec # frozen_string_literal: false.

Si vous voulez qu'un littéral de chaîne soit modifiable quel que soit le paramètre global ou par fichier, vous pouvez le préfixer avec l' +opérateur unaire (en faisant attention à la priorité de l'opérateur) ou l'appeler .dup:

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

Vous pouvez également geler une chaîne modifiable (non gelée) avec unaire -.

Dave Schweisguth
la source
25
Une chose importante à noter concernant le gel des chaînes est qu'elle améliore les performances de l'application . Voir aussi ici
Andres Ehrenpreis
2
@ dave-schweisguth Ne devrait-on pas s'attendre -"foo"à être le même que "foo".freeze? Lorsque je vérifie, (-"foo").__id__j'obtiens une valeur différente à chaque fois, mais elle "foo".freeze.__id__est la même à chaque fois. Des idées?
lilole
Je me demande si cette fonction est le problème, elle ne semble être appelée qu'avec le moins unaire. github.com/ruby/ruby/blob/trunk/string.c#L2572
lilole
2
-sert à dédupliquer la chaîne pour économiser de la mémoire, en plus de renvoyer une chaîne figée.
eregon
9
Bien que vous puissiez toujours utiliser le commentaire magique, Matz a officiellement décidé de ne pas rendre tous les littéraux de chaîne immuables par défaut dans Ruby 3: bugs.ruby-lang.org/issues/11473#note-53
Konstantin Tikhonov
44

Il améliore les performances des applications en n'allouant pas de nouvel espace pour la même chaîne, ce qui permet également de gagner du temps pour les tâches de récupération de place. Comment? lorsque vous figez un littéral de chaîne (objet chaîne), vous dites à Ruby de ne laisser aucun de vos programmes modifier le littéral de chaîne (objet).

Quelques observations évidentes à garder à l'esprit.

1. En gelant les littéraux de chaîne, vous ne lui allouez pas de nouvel espace mémoire.

Exemple:

Sans commentaire magique alloue un nouvel espace pour la même chaîne (Observez les différents ID d'objet imprimés)

def hello_id
  a = 'hello'
  a.object_id
end

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

Avec un commentaire magique , ruby ​​alloue de l'espace une seule fois

# frozen_string_literal: true

def hello_id
  a = 'hello'
  a.object_id
end

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

2. En gelant les littéraux de chaîne, votre programme lèvera une exception lors de la tentative de modification du littéral de chaîne.

Exemple:

Sans commentaire magique , vous pouvez modifier les littéraux de chaîne.

name = 'Johny'
name << ' Cash'

puts name     #=> Johny Cash

Avec un commentaire magique , une exception sera levée lorsque vous modifiez les littéraux de chaîne

# frozen_string_literal: true

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

puts name      

Il y a toujours plus à apprendre et à être flexible:

imechemi
la source
Ceci est une réponse plus intuitive.
Jin Lim
20

Dans Ruby 3.0. Matz (le créateur de Ruby) a décidé de rendre tous les littéraux String figés par défaut.

Vous pouvez utiliser dans Ruby 2.x. Ajoutez simplement ce commentaire dans la première ligne de vos fichiers.

# frozen_string_literal: true

Le commentaire ci-dessus en haut d'un fichier modifie la sémantique des littéraux de chaîne statiques dans le fichier. Les littéraux de chaîne statiques seront figés et retourneront toujours le même objet. (La sémantique des littéraux de chaînes dynamiques n'est pas modifiée.)

Cette façon présente les avantages suivants:

Aucun laid f-suffixe. Aucune erreur de syntaxe sur les anciens Ruby. Nous n'avons besoin que d'une ligne pour chaque fichier.

Veuillez lire ce sujet pour plus d'informations.

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

Alexandr
la source
Malheureusement, ce commentaire ne fonctionne pas pour les chaînes dans les tableaux, ils doivent donc être gelés explicitement
ToTenMilan
3
Malheureusement, ce ne sera pas en rubis 3 bugs.ruby-lang.org/issues/11473#note-53
zhisme