O que o comentário "frozen_string_literal: true" faz?

226

Este é o rspecbinstub no diretório do meu projeto.

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

O que isso pretende fazer?

# frozen_string_literal: true
messanjah
fonte

Respostas:

314

# frozen_string_literal: trueé um comentário mágico, suportado pela primeira vez no Ruby 2.3, que informa ao Ruby que todos os literais de string no arquivo estão implicitamente congelados, como se #freezetivessem sido chamados em cada um deles. Ou seja, se um literal de string for definido em um arquivo com esse comentário, e você chamar um método nessa string que a modifique, como <<você obterá RuntimeError: can't modify frozen String.

O comentário deve estar na primeira linha do arquivo.

No Ruby 2.3, você pode usar esse comentário mágico para se preparar para literais de string congelados, sendo o padrão no Ruby 3 .

No Ruby 2.3, execute o --enable=frozen-string-literalsinalizador e , no Ruby 3, os literais de strings são congelados em todos os arquivos. Você pode substituir a configuração global por # frozen_string_literal: false.

Se você deseja que uma literal de cadeia de caracteres seja mutável, independentemente da configuração global ou por arquivo, você pode prefixá-la com o +operador unário (tomando cuidado com a precedência do operador) ou invocá .dup-la:

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

Você também pode congelar uma sequência mutável (descongelada) com unária -.

Dave Schweisguth
fonte
24
O ponto importante a ser observado sobre o congelamento de strings é que ele melhora o desempenho do aplicativo . Veja também aqui
Andres Ehrenpreis 29/06
2
@ dave-schweisguth Não devemos esperar -"foo"ser iguais "foo".freeze? Quando eu verifico (-"foo").__id__, recebo um valor diferente a cada vez, mas sempre o "foo".freeze.__id__mesmo. Alguma ideia?
lilole
Gostaria de saber se esta função é a questão, parece ser chamada apenas com o menos unário. github.com/ruby/ruby/blob/trunk/string.c#L2572
lilole
2
-é para desduplicar a String para economizar memória, além de retornar uma String congelada.
eregon
9
Enquanto você ainda pode usar o comentário mágico, Matz decidiu oficialmente não tornar todos os literais de string imutáveis ​​por padrão no Ruby 3: bugs.ruby-lang.org/issues/11473#note-53
Konstantin Tikhonov
44

Ele melhora o desempenho do aplicativo ao não alocar novo espaço para a mesma sequência, economizando tempo para tarefas de coleta de lixo. Quão? quando você congela uma string literal (objeto de string), você está dizendo ao Ruby para não permitir que nenhum de seus programas modifique a string literal (objeto).

Algumas observações óbvias a serem lembradas.

1. Ao congelar literais de string, você não está alocando novo espaço de memória para ele.

Exemplo:

Sem comentário mágico, aloca novo espaço para a mesma sequência (observe os diferentes IDs de objeto impressos)

def hello_id
  a = 'hello'
  a.object_id
end

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

Com comentários mágicos , o ruby ​​aloca espaço apenas uma vez

# frozen_string_literal: true

def hello_id
  a = 'hello'
  a.object_id
end

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

2. Ao congelar literais de string, seu programa gerará uma exceção ao tentar modificar o literal de string.

Exemplo:

Sem comentário mágico , você pode modificar os literais da string.

name = 'Johny'
name << ' Cash'

puts name     #=> Johny Cash

Com o comentário mágico , uma exceção será gerada quando você modificar literais de string

# frozen_string_literal: true

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

puts name      

Há sempre mais para aprender e ser flexível:

imechemi
fonte
Esta é uma resposta mais intuitiva.
Jin Lim
20

No Ruby 3.0. Matz (criador de Ruby) decidiu tornar todos os literais de String congelados por padrão.

Você pode usar no Ruby 2.x. Basta adicionar este comentário na primeira linha dos seus arquivos.

# frozen_string_literal: true

O comentário acima na parte superior de um arquivo altera a semântica dos literais de seqüência de caracteres estáticos no arquivo. Os literais de string estáticos serão congelados e sempre retornam o mesmo objeto. (A semântica dos literais de cadeia dinâmica não é alterada.)

Dessa maneira, há os seguintes benefícios:

Nenhum feio sufixo-f. Nenhum erro de sintaxe no Ruby mais antigo. Precisamos apenas de uma linha para cada arquivo.

Por favor, leia este tópico para obter mais informações.

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

Alexandr
fonte
Infelizmente, esse comentário não funciona para cadeias de caracteres em matrizes, portanto elas ainda precisam ser congeladas explicitamente #
ToTenMilan
3
Infelizmente, este não estará em ruby 3 bugs.ruby-lang.org/issues/11473#note-53
zhisme