评论"frozen_string_literal:true"有什么作用?

mes*_*jah 188 ruby string immutability ruby-2.3

这是rspec我项目目录中的binstub.

#!/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")
Run Code Online (Sandbox Code Playgroud)

这是打算做什么的?

# frozen_string_literal: true
Run Code Online (Sandbox Code Playgroud)

Dav*_*uth 271

# 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
Run Code Online (Sandbox Code Playgroud)

你也可以用一元冻结一个可变(解冻)的字符串-.

  • 关于冻结字符串的重要注意事项是它[提高应用程序的性能](https://bugs.ruby-lang.org/issues/8976#note-30).另见[here](https://www.lucascaton.com.br/2016/01/19/what-is-frozen_string_literal-in-ruby/) (17认同)
  • 虽然您仍然可以使用魔术注释,但是Matz正式决定在Ruby 3中默认不使所有字符串文字保持不变:https://bugs.ruby-lang.org/issues/11473#note-53 (6认同)
  • @Eddie,因为大多数语言将字符串视为不可变的,这有助于确保您不会意外修改它们并可以提高性能。程序中较少的状态变化意味着较低的复杂性。最好在仔细考虑后选择可变性,而不是默认设置所有内容都可变。[什么是不变性以及为什么我应该担心它?](/sf/ask/43586511/)可能会有所帮助。 (3认同)
  • @ dave-schweisguth我们不应该期望` - "foo"`与``foo".freeze`相同?当我检查`( - "foo").__ id__`时,我每次都得到一个不同的值,但是``foo".freeze .__ id__`每次都是相同的.有任何想法吗? (2认同)
  • `-` 用于对 String 进行重复数据删除以节省内存,此外还返回一个冻结的 String。 (2认同)
  • 我还是不明白。为什么需要它? (2认同)

ime*_*emi 19

通过不为同一字符串分配新空间来提高应用程序性能,从而也节省了垃圾收集工作的时间。怎么样?当冻结字符串(字符串对象)时,是在告诉Ruby不要让任何程序修改字符串(对象)。

注意一些明显的观察。

1.通过冻结字符串文字,您无需为其分配新的内存空间。

例:

没有魔术注释,将为同一字符串分配新的空间(观察打印的不同对象ID)

def hello_id
  a = 'hello'
  a.object_id
end

puts hello_id   #=> 70244568358640
puts hello_id   #=> 70244568358500
Run Code Online (Sandbox Code Playgroud)

通过魔术注释,ruby仅分配一次空间

# frozen_string_literal: true

def hello_id
  a = 'hello'
  a.object_id
end

puts hello_id   #=> 70244568358640
puts hello_id   #=> 70244568358640
Run Code Online (Sandbox Code Playgroud)

2.通过冻结字符串文字,您的程序在尝试修改字符串文字时将引发异常。

例:

如果没有魔术注释,则可以修改字符串文字。

name = 'Johny'
name << ' Cash'

puts name     #=> Johny Cash
Run Code Online (Sandbox Code Playgroud)

使用魔术注释时,修改字符串文字时将引发异常

# frozen_string_literal: true

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

puts name      
Run Code Online (Sandbox Code Playgroud)

总会有更多的东西要学习并且要灵活:

  • 这是一个更直观的答案。 (9认同)

Ale*_*ndr 18

在Ruby 3.0中.Matz(Ruby的创建者)决定默认冻结所有String文字.

你可以在Ruby 2.x中使用.只需在文件的第一行添加此注释即可.

# frozen_string_literal: true
Run Code Online (Sandbox Code Playgroud)

文件顶部的上述注释会更改文件中静态字符串文字的语义.静态字符串文字将被冻结并始终返回相同的对象.(动态字符串文字的语义不会改变.)

这种方式有以下好处:

没有丑陋的f后缀.旧Ruby上没有语法错误.我们每个文件只需要一行.

请阅读本主题以获取更多信息.

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

  • 不幸的是,这不会在 ruby​​ 3 https://bugs.ruby-lang.org/issues/11473#note-53 (8认同)
  • @ToTenMilan 在 Ruby 3.0.6 中,frozen_string_literal 注释对数组中的字符串有效,但字符串无法修改。您发现这在哪个 Ruby 版本中不起作用? (2认同)