Was macht der Kommentar "Frozen_String_Literal: True"?


226

Dies ist der rspecbinstub in meinem Projektverzeichnis.

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

Was soll das tun?

# frozen_string_literal: true

Antworten:


314

# frozen_string_literal: trueist ein magischer Kommentar, der zum ersten Mal in Ruby 2.3 unterstützt wird und Ruby mitteilt, dass alle String-Literale in der Datei implizit eingefroren sind, als ob #freezesie für jeden von ihnen aufgerufen worden wären . Das heißt, wenn ein String - Literal in einer Datei mit diesem Kommentar definiert ist, und Sie rufen eine Methode auf diesem String, ändert es, wie <<, die Sie erhalten RuntimeError: can't modify frozen String.

Der Kommentar muss in der ersten Zeile der Datei stehen.

In Ruby 2.3 können Sie diesen magischen Kommentar verwenden , um sich darauf vorzubereiten, dass eingefrorene Zeichenfolgenliterale in Ruby 3 die Standardeinstellung sind .

In Ruby 2.3, das mit dem --enable=frozen-string-literalFlag ausgeführt wird, und in Ruby 3 werden Zeichenfolgenliterale in allen Dateien eingefroren. Sie können die globale Einstellung mit überschreiben # frozen_string_literal: false.

Wenn Sie möchten, dass ein Zeichenfolgenliteral unabhängig von der globalen Einstellung oder der Einstellung pro Datei veränderbar ist, können Sie ihm den unären +Operator voranstellen (wobei Sie auf die Priorität des Operators achten) oder ihn aufrufen .dup:

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

Sie können auch eine veränderbare (nicht gefrorene) Zeichenfolge mit unary einfrieren -.


24
Beim Einfrieren von Zeichenfolgen ist zu beachten, dass die Leistung der App verbessert wird . Siehe auch hier
Andres Ehrenpreis

2
@ dave-schweisguth Sollten wir nicht erwarten -"foo", dass es dasselbe ist wie "foo".freeze? Wenn ich nachschaue, (-"foo").__id__erhalte ich jedes Mal einen anderen Wert, der jedoch "foo".freeze.__id__jedes Mal gleich ist. Irgendwelche Ideen?
Lilole

Ich frage mich, ob diese Funktion das Problem ist, sie scheint nur mit dem unären Minus aufgerufen zu werden. github.com/ruby/ruby/blob/trunk/string.c#L2572
Lilole

2
-dient zum Deduplizieren des Strings, um Speicherplatz zu sparen, und zum Zurückgeben eines eingefrorenen Strings.
Oregon

9
Während Sie den magischen Kommentar weiterhin verwenden können, hat Matz offiziell entschieden, nicht alle String-Literale in Ruby 3 standardmäßig unveränderlich zu machen: bugs.ruby-lang.org/issues/11473#note-53
Konstantin Tikhonov

43

Es verbessert die Anwendungsleistung, indem nicht neuer Speicherplatz für dieselbe Zeichenfolge zugewiesen wird, wodurch auch Zeit für die Speicherbereinigung gespart wird. Wie? Wenn Sie ein String-Literal (String-Objekt) einfrieren, weisen Sie Ruby an, dass keines Ihrer Programme das String-Literal (Objekt) ändern darf.

Einige offensichtliche Beobachtungen zu beachten.

1. Indem Sie String-Literale einfrieren, weisen Sie keinen neuen Speicherplatz dafür zu.

Beispiel:

Ohne magischen Kommentar wird der gleichen Zeichenfolge neuer Speicherplatz zugewiesen (Beachten Sie die verschiedenen gedruckten Objekt-IDs).

def hello_id
  a = 'hello'
  a.object_id
end

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

Mit einem magischen Kommentar weist Ruby nur einmal Speicherplatz zu

# frozen_string_literal: true

def hello_id
  a = 'hello'
  a.object_id
end

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

2. Wenn Sie String-Literale einfrieren, löst Ihr Programm eine Ausnahme aus, wenn Sie versuchen, das String-Literal zu ändern.

Beispiel:

Ohne magischen Kommentar können Sie die Zeichenfolgenliterale ändern.

name = 'Johny'
name << ' Cash'

puts name     #=> Johny Cash

Bei einem magischen Kommentar wird eine Ausnahme ausgelöst, wenn Sie Zeichenfolgenliterale ändern

# frozen_string_literal: true

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

puts name      

Es gibt immer mehr zu lernen und flexibel zu sein:


Dies ist eine intuitivere Antwort.
Jin Lim

20

In Ruby 3.0. Matz (Rubys Schöpfer) hat beschlossen, alle String-Literale standardmäßig einzufrieren.

Sie können in Ruby 2.x verwenden. Fügen Sie diesen Kommentar einfach in die erste Zeile Ihrer Dateien ein.

# frozen_string_literal: true

Der obige Kommentar oben in einer Datei ändert die Semantik statischer Zeichenfolgenliterale in der Datei. Die statischen Zeichenfolgenliterale werden eingefroren und geben immer dasselbe Objekt zurück. (Die Semantik dynamischer String-Literale wird nicht geändert.)

Dieser Weg hat folgende Vorteile:

Kein hässliches F-Suffix. Kein Syntaxfehler bei älteren Ruby. Wir brauchen nur eine Zeile für jede Datei.

Bitte lesen Sie dieses Thema für weitere Informationen.

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


Leider funktioniert dieser Kommentar nicht für Strings in Arrays, so dass sie noch explizit
eingefroren

3
Leider wird dies nicht in Ruby 3 Bugs.ruby-lang.org/issues/11473#note-53
Zhisme
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.