質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

Ruby frozen_string_literal について

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 1,747

E-T

score 12

 前置き

突然の投稿失礼します。
Ruby開発初心者なのですが、
知識と経験不足で開発の定石や基礎部分がうまく理解できておらず質問を投稿させていただきます。

先月Rubyで開発を行い、ソースコードのレビューで指摘を頂いた時に色々と疑問に思ったことがあり、
その中で一点どうしても理解できないところがありましたのでご助言をお願いします。

指摘を受けた部分は、rubocopで構文チェックを行いソースコードを訂正した箇所にあります。
rubocopを実行させた際に

Missing frozen string literal comment.


という上記の警告が発生したため、調査して下記のコメントを付与することで問題を解決していました。

# frozen_string_literal: true


この対応を行った箇所に対して
「その記述は必要ですか?」
というご指摘をレビューの際にいただき、今一度必要性を調査したところ謎が深まりわからなくなりました。
どうかご教示をお願いします。

環境

Ruby : 2.3.1
Rails : 5.0.2
構文チェック : rubocop

疑問点

  • 通常の開発を行う際は、rubocopのfrozen_string_literalに関してどう対応しているのか。
    (.rubocop.ymlに設定するのか、警告の出たソースコードを修正する等)
    ※その対応の理由も教えていただきたいです。

調査したところ、文字列リテラルの扱いに関する記述・対応ということ、
rubocopが標準でfrozen_string_literalを検査していること、
またrubyのversionが3.0になる際に大きく関わるということは多少理解しました。

↓参考にさせて頂いた資料
http://d.hatena.ne.jp/ku-ma-me/20151004/p1
http://www.task-notes.com/entry/20160831/1472572735


見当外れなことをお聞きしているかもしれませんが、是非ご教示お願いします。
よろしくお願いします。
必要な情報などがございましたらご提示致しますのでその際はお手数ですがお声掛けしていただけると幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+4

 frozen_string_literalについて

rubyにおいて、文字列(Stringオブジェクト)はmutable(破壊的に変更可能)なデータです。
ruby reference: class String
例えば、以下のコードは変数str/str2に一度しか代入していないにもかかわらず、参照のタイミングによって内容が異なっています。

str = 'test'
str2 = str

print str, str2 # => testtest
str.upcase!
print str, str2 # => TESTTEST

一般に、オブジェクトの破壊的変更はコードの可読性を下げ、バグを誘発する傾向にあります。あるオブジェクトをコードのどこかで破壊的に変更すると、そのオブジェクトを参照している箇所全体に影響を与えるからです(上記コードのstr/str2の関係)。
そこで、従来のrubyでは文字列の破壊的変更を禁止するため、freezeメソッドを呼ぶといった対策を取ってきました。

str = 'test'
str.freeze
str.upcase! # => RuntimeError: can't modify frozen String

しかし、文字列というごく一般的なデータを取り扱うために都度freezeを付けるのは面倒臭い + freezeが必要/不要を考えず、文字列に片っ端からfreezeを付ける実装が跋扈してきたということから、「そもそもデフォルトで文字列をimmutable(破壊的な変更不可)にしてしまおう」という方針が、ruby3.0以降で決定しています。
 [Ruby] Ruby 3.0 の特大の非互換について

そして、将来ruby3.0がリリースされた時にruby2.x系からスムーズに以降できるよう、「デフォルトでStringをimmutableにする」という機能をruby2.x系で限定的に取り込んだのがfrozen_string_literalというマジックコメントです。

 frozen_string_literalの対応

私は原則、rubocopの指針に従ってfronze_string_literal: trueをソースコード内に追加するようにしています。その方が、将来バージョンアップ時の手間が減る(ruby3.0では、frozen_string_literalは単なるコメントとして扱われる予定)ことと、デフォルトでimmutableにした方が予期せぬバグを抱えにくいからです。
ただ、config系のファイル、テストコード、migrationファイルはrubocopによるチェックの対象外としています。
migrationファイルはほぼrailsで自動生成したものをそのまま使う、configはそもそも設定を書き下すだけでデータ操作はしない、テストコードは実際の動作に関わらない、といった理由から、そこまで厳密なコーディングをしなくても良いだろう、という判断です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/02 12:04

    ありがとうございます!
    大変わかりやすく解説していただき、かなり理解を深めることができました。
    rubocopの設定も非常に参考になりました。

    解説して頂いた情報と、記事を読んだ所感ですが、私も引き続きfrozen_string_literal: trueをソースコードに追記する対応を維持していこうと思います。
    ただ、今回は最初に「rubocopの対象ファイルはどうするか、規約はどの程度のものを設定するか」という部分をしっかり策定できていなかったため、今後はその部分の流れも頭に入れてから構文チェックを走らせていこうと思います。

    この度は本当にありがとうございました。
    重ねて御礼申し上げます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る