“frozen_string_literal : true”라는 주석은 무엇을합니까?


226

이것은 rspec내 프로젝트 디렉토리 의 쓰레기통입니다.

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

이것은 무엇을하기위한 것입니까?

# frozen_string_literal: true

답변:


314

# frozen_string_literal: trueRuby 2.3에서 처음으로 지원되는 마법의 주석으로, 파일에있는 모든 문자열 리터럴이 #freeze각각에 대해 호출 된 것처럼 암시 적으로 고정되었음을 Ruby에 알려줍니다 . 문자열 리터럴이 댓글을 가진 파일에 정의되어있는 경우 즉, 그리고 당신이하는 등의 수정을, 해당 문자열에 대한 메소드를 호출 <<, 당신은 얻을 것이다 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

unary로 변경 가능 (동결 해제) 문자열을 고정 할 수도 있습니다 -.


24
고정 문자열과 관련하여주의해야 할 중요한 점 은 앱의 성능향상 된다는 것 입니다. 참조 여기
안드레스 Ehrenpreis

2
@ dave-schweisguth 우리 -"foo"와 같을 것으로 기 대해서는 안 "foo".freeze됩니까? 확인하면 (-"foo").__id__매번 다른 값을 얻지 만 "foo".freeze.__id__매번 동일합니다. 어떤 아이디어?
lilole

이 함수가 문제인지 궁금해, 단항 마이너스로만 호출되는 것 같습니다. github.com/ruby/ruby/blob/trunk/string.c#L2572
lilole

2
-고정 된 문자열을 반환 할뿐만 아니라 메모리를 절약하기 위해 문자열을 중복 제거하기위한 것입니다.
eregon

9
여전히 마법의 주석을 사용할 수 있지만 Matz는 공식적으로 Ruby 3에서 모든 문자열 리터럴을 기본적으로 변경할 수 없도록 결정했습니다. bugs.ruby-lang.org/issues/11473#note-53
Konstantin Tikhonov

43

동일한 문자열에 새 공간을 할당하지 않아 응용 프로그램 성능이 향상되어 가비지 수집 작업 시간이 절약됩니다. 어떻게? 문자열 리터럴 (문자열 객체)을 고정하면 프로그램에서 문자열 리터럴 (객체)을 수정하지 않도록 Ruby에 지시합니다.

명심해야 할 몇 가지 명백한 관찰.

1. 문자열 리터럴을 고정하면 새로운 메모리 공간이 할당되지 않습니다.

예:

마술 주석이 없으면 동일한 문자열에 새 공간을 할당합니다 (인쇄 된 다른 객체 ID를 준수하십시오)

def hello_id
  a = 'hello'
  a.object_id
end

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

매직 코멘트 로 루비는 한 번만 공간을 할당합니다.

# frozen_string_literal: true

def hello_id
  a = 'hello'
  a.object_id
end

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

2. 문자열 리터럴을 고정하면 문자열 리터럴을 수정하려고 할 때 프로그램에서 예외가 발생합니다.

예:

magic comment가 없으면 문자열 리터럴을 수정할 수 있습니다.

name = 'Johny'
name << ' Cash'

puts name     #=> Johny Cash

magic comment를 사용하면 문자열 리터럴을 수정할 때 예외가 발생합니다.

# frozen_string_literal: true

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

puts name      

항상 배우고 융통성이 있어야합니다.


더 직관적 인 답변입니다.
Jin Lim

20

루비 3.0. Matz (Ruby의 제작자)는 기본적으로 모든 문자열 리터럴을 고정하기로 결정했습니다.

Ruby 2.x에서 사용할 수 있습니다. 파일의 첫 줄에이 주석을 추가하십시오.

# frozen_string_literal: true

파일 맨 위의 주석은 파일에서 정적 문자열 리터럴의 의미를 변경합니다. 정적 문자열 리터럴은 고정되며 항상 동일한 객체를 반환합니다. (동적 문자열 리터럴의 의미는 변경되지 않습니다.)

이 방법은 다음과 같은 이점이 있습니다.

추악한 f- 접미사가 없습니다. 이전 Ruby에서는 구문 오류가 없습니다. 각 파일마다 한 줄만 있으면됩니다.

자세한 내용은이 주제를 읽으십시오.

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


불행히도이 주석은 배열의 문자열에는 적용되지 않으므로 여전히 명시 적으로 고정해야합니다.
ToTenMilan

3
불행히도 이것은 루비 3에 있지 않을 것입니다. bugs.ruby-lang.org/issues/11473#note-53
zhisme
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.