Code Fix

中級

FrozenError: can't modify frozen String の原因と直し方

freezeしたオブジェクトを破壊的メソッド(<<やupcase!など)で変更しようとすると、FrozenErrorになります。定数として扱いたい文字列にfreezeを付けると、以後は書き換えが禁止されます。

エラーメッセージの読み方

main.rb:2:in `<main>': can't modify frozen String: "Alice" (FrozenError)
main.rb
ファイル名
2
行番号 — 実際にクラッシュした行
<main>
発生場所 — <main> ならトップレベル、メソッド名ならそのメソッドの中
FrozenError
例外クラス — 何が起きたか。ここを検索するのが最短です
can't modify frozen String: "Alice"
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  name = "Alice".freeze
 2  puts(name << " Smith")
               ^
main.rb:2:in `<main>': can't modify frozen String: "Alice" (FrozenError)

<<は文字列そのものを書き換える破壊的メソッドです。freezeした文字列には使えないため、新しい文字列を作る+に置き換える必要があります。

直し方: <<+ にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  title = "Manager".freeze
 2  puts(title << "!")
                ^
main.rb:2:in `<main>': can't modify frozen String: "Manager" (FrozenError)

定数のように扱いたい文字列にfreezeを付けると、以後は破壊的メソッドによる変更が一律で禁止されます。

直し方: <<+ にします。

この問題を解いてみる →

パターン3

 1  code = "AB".freeze
 2  puts(code << "12")
               ^
main.rb:2:in `<main>': can't modify frozen String: "AB" (FrozenError)

freezeは変数への再代入ではなく、オブジェクトそのものを凍結します。中身を変える操作はすべて拒否されます。

直し方: <<+ にします。

この問題を解いてみる →

パターン4

 1  tag = "ruby".freeze
 2  puts(tag << "-lang")
              ^
main.rb:2:in `<main>': can't modify frozen String: "ruby" (FrozenError)

+は元の文字列を変えずに新しい文字列を作るので、freezeされたオブジェクトにも安全に使えます。

直し方: <<+ にします。

この問題を解いてみる →

パターン5

 1  prefix = "Mr.".freeze
 2  puts(prefix << " Smith")
                 ^
main.rb:2:in `<main>': can't modify frozen String: "Mr." (FrozenError)

破壊的メソッド(!や<<が付くもの)を使う前に、レシーバがfreezeされていないか意識する必要があります。

直し方: <<+ にします。

この問題を解いてみる →

よくある誤解

「freezeは変数への再代入を禁止するだけのはず」という思い込みは誤りです。freezeはオブジェクトそのものを凍結するため、破壊的メソッドによる中身の変更も一律で禁止されます。

まとめ

FrozenError: can't modify frozen Stringは中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)