Nhận xét về Frozen Frozen_liter_literal: true có nghĩa là gì?


226

Đây là rspecbinstub trong thư mục dự án của tôi.

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

Điều này dự định để làm gì?

# frozen_string_literal: true

Câu trả lời:


314

# frozen_string_literal: truelà một nhận xét ma thuật, được hỗ trợ lần đầu tiên trong Ruby 2.3, nói với Ruby rằng tất cả các chuỗi ký tự trong tệp đều bị đóng băng hoàn toàn, như thể #freezeđã được gọi trên mỗi trong số chúng. Đó là, nếu một chuỗi ký tự được định nghĩa trong một tệp có nhận xét này và bạn gọi một phương thức trên chuỗi đó để sửa đổi nó, chẳng hạn như <<, bạn sẽ nhận được RuntimeError: can't modify frozen String.

Nhận xét phải ở dòng đầu tiên của tệp.

Trong Ruby 2.3, bạn có thể sử dụng nhận xét ma thuật này để chuẩn bị cho các chuỗi ký tự đóng băng được mặc định trong Ruby 3 .

Trong Ruby 2.3 chạy với --enable=frozen-string-literalcờ và trong Ruby 3, chuỗi ký tự được đóng băng trong tất cả các tệp. Bạn có thể ghi đè cài đặt chung với # frozen_string_literal: false.

Nếu bạn muốn một chuỗi ký tự có thể thay đổi bất kể cài đặt toàn cục hoặc mỗi tệp, bạn có thể đặt tiền tố cho toán tử đơn nguyên +(cẩn thận với quyền ưu tiên của toán tử) hoặc gọi .dupnó:

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

Bạn cũng có thể đóng băng một chuỗi có thể thay đổi (không đóng băng) với unary -.


24
Điều quan trọng cần lưu ý liên quan đến chuỗi đóng băng là nó cải thiện hiệu suất của ứng dụng . Xem thêm tại đây
Andres Ehrenpreis

2
@ dave-schweisguth Chúng ta không nên -"foo"giống như "foo".freezevậy sao? Khi tôi kiểm tra (-"foo").__id__tôi nhận được một giá trị khác nhau mỗi lần, nhưng "foo".freeze.__id__mỗi lần đều giống nhau. Có ý kiến ​​gì không?
lilole

Tôi tự hỏi nếu chức năng này là vấn đề, nó dường như chỉ được gọi với dấu trừ đơn nguyên. github.com/ruby/ruby/blob/trunk/opes.c#L2572
lilole

2
-là để sao chép Chuỗi để tiết kiệm bộ nhớ, ngoài việc trả về Chuỗi bị đóng băng.
eregon

9
Mặc dù bạn vẫn có thể sử dụng nhận xét ma thuật, Matz đã chính thức quyết định không biến tất cả các chuỗi chữ theo mặc định trong Ruby 3: bug.ruby-lang.org/issues/11473#note-53
Konstantin Tikhonov

44

Nó cải thiện hiệu suất ứng dụng bằng cách không phân bổ không gian mới cho cùng một chuỗi, do đó cũng tiết kiệm thời gian cho các công việc thu gom rác. Làm sao? khi bạn đóng băng một chuỗi ký tự (đối tượng chuỗi), bạn đang nói với Ruby rằng đừng để bất kỳ chương trình nào của bạn sửa đổi chuỗi ký tự (đối tượng).

Một số quan sát rõ ràng để ghi nhớ.

1. Bằng cách đóng băng chuỗi ký tự, bạn không phân bổ không gian bộ nhớ mới cho nó.

Thí dụ:

Không có nhận xét ma thuật phân bổ không gian mới cho cùng một chuỗi (Quan sát các ID đối tượng khác nhau được in)

def hello_id
  a = 'hello'
  a.object_id
end

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

Với nhận xét ma thuật , ruby ​​chỉ phân bổ không gian một lần

# frozen_string_literal: true

def hello_id
  a = 'hello'
  a.object_id
end

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

2. Bằng cách đóng băng chuỗi ký tự, chương trình của bạn sẽ đưa ra một ngoại lệ khi cố gắng sửa đổi chuỗi ký tự.

Thí dụ:

Nếu không có bình luận ma thuật , bạn có thể sửa đổi chuỗi ký tự.

name = 'Johny'
name << ' Cash'

puts name     #=> Johny Cash

Với nhận xét ma thuật , một ngoại lệ sẽ được nêu ra khi bạn sửa đổi chuỗi ký tự

# frozen_string_literal: true

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

puts name      

Luôn có nhiều thứ để học và linh hoạt:


Đây là một câu trả lời trực quan hơn.
Jin Lim

20

Trong Ruby 3.0. Matz (người tạo ra Ruby) đã quyết định làm cho tất cả các chuỗi ký tự Chuỗi được đóng băng theo mặc định.

Bạn có thể sử dụng trong Ruby 2.x. Chỉ cần thêm nhận xét này trong dòng đầu tiên của tập tin của bạn.

# frozen_string_literal: true

Nhận xét trên ở đầu tệp thay đổi ngữ nghĩa của chuỗi ký tự tĩnh trong tệp. Các chuỗi ký tự tĩnh sẽ được đóng băng và luôn trả về cùng một đối tượng. (Ngữ nghĩa của chuỗi ký tự động không thay đổi.)

Cách này có những lợi ích sau:

Không có hậu tố f xấu xí. Không có lỗi cú pháp trên Ruby cũ. Chúng tôi chỉ cần một dòng cho mỗi tập tin.

Xin vui lòng, đọc chủ đề này để biết thêm thông tin.

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


Thật không may, nhận xét này không hoạt động đối với các chuỗi trong mảng, vì vậy chúng vẫn cần được đóng băng rõ ràng
ToTenMilan

3
Thật không may, điều này sẽ không có trong ruby ​​3 bug.ruby-lang.org/issues/11473#note-53
lang.org/issues/11473#note
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.