ZENET大貫です。
今回は、業務で遭遇した Ruby の非推奨警告
「warning: literal string will be frozen in the future」
の回避方法について書いていきたいと思います。
目次
- 非推奨警告とは何か
- warning: literal string will be frozen in the futureについて
- 「dup」を使い warning: literal string will be frozen in the future を回避する方法
- 「dup」とは何か
- 「dup」と「clone」の違い
- まとめ
非推奨警告とは何か
Rubyでは、将来的に問題が発生しそうなコードに対して警告が表示されます。
Ruby 2.7以降、警告はカテゴリ別に分類されており、例えば以下のようなものがあります。
-W:deprecated(非推奨)-W:experimental(実験的)-W:performance(性能)
「非推奨警告」は、現時点では動作しているものの、将来的には動作しなくなる可能性があるコードに対して表示される警告です。
warning: literal string will be frozen in the futureについて
今回扱う
「warning: literal string will be frozen in the future」 は -W:deprecated(非推奨)に分類される警告です。
この警告は、文字列リテラルに対して破壊的な操作を行おうとした場合に表示されます。
Ruby 3.0以降では、文字列リテラル("テスト" のようにコード中に直接書かれた文字列)が自動的に freeze される仕様になります。
そのため Ruby 2.7では、
「今は動くけど、将来はエラーになるので今のうちに直してね」
という意味で、この警告が表示されます。
例
a = "テスト" p a b = a.force_encoding("EUC-JP") # warning: literal string will be frozen in the future (run with --debug-frozen-string-literal for more information) p a # "テスト" p b # "\xE3\x83\x86\xE3\x82\x{B9E3}\x83\x88"
force_encoding は破壊的メソッドであり、文字列オブジェクト自体を変更します。
このような操作を文字列リテラルに対して行っているため、非推奨警告が出ています。
「dup」を使い warning: literal string will be frozen in the future を回避する方法
この警告を回避する方法として、dup メソッドを使用する方法があります。
dup を使うことで、元の文字列とは別の新しいオブジェクトを作成し、そのオブジェクトに対して破壊的な操作を行うことができます。
例
a = "テスト" p a b = a.dup.force_encoding("EUC-JP") p a # "テスト" p b # "\xE3\x83\x86\xE3\x82\x{B9E3}\x83\x88"
このように dup を使うことで元の a に影響を与えることなく、新しい b にエンコーディング変更を反映させることができます。
「dup」とは何か
dup は、オブジェクトの内容を保持したまま、新しいオブジェクト(浅いコピー)を作成するメソッドです。
コピーされたオブジェクトは、元のオブジェクトとは別物であり、フリーズ状態も引き継ぎません。
そのため破壊的な変更を行っても元のオブジェクトには影響がなく、非推奨警告も発生しません。
「dup」と「clone」の違い
dup と似たメソッドに clone があります。
clone もオブジェクトの浅いコピーを作成しますが、以下の点が異なります。
- フリーズ状態を引き継ぐ
- 特異メソッドなどのメタ情報も引き継ぐ
そのため、コピー元がフリーズされる予定の文字列リテラルである場合、clone したオブジェクトも同様にフリーズ状態を引き継ぎ、破壊的操作ができません。
例
a = "テスト" p a b = a.clone.force_encoding("EUC-JP") # warning: literal string will be frozen in the future (run with --debug-frozen-string-literal for more information) p a # "テスト" p b # "\xE3\x83\x86\xE3\x82\x{B9E3}\x83\x88"
このように clone を使うと元のオブジェクトのフリーズ状態を引き継いでしまうため、警告を回避できません。
まとめ
Rubyの非推奨警告
「warning: literal string will be frozen in the future」
は、将来フリーズされる文字列リテラルに対して破壊的操作を行っていることを知らせる警告です。
この警告を回避するには、dup を使って新しいオブジェクトを作成し、そのオブジェクトに対して操作を行うのが有効です。
一方で、clone はフリーズ状態を引き継ぐため、今回のケースでは警告を回避できません。
dup と clone の違いを理解し、用途に応じて使い分けることが重要です。
