中級のRubyエラー 60問
12種類のエラーを、それぞれ複数パターンずつ収録しています。
- FrozenError: can't modify frozen String の原因と直し方freezeしたオブジェクトを破壊的メソッド(<<やupcase!など)で変更しようとすると、FrozenErrorになります。定数として扱いたい文字列にfreezeを付けると、以後は書き換えが禁止されます。
- Hash.new([]) のデフォルト値は全キーで同じ配列を共有してしまうHash.new([])で作ったハッシュは、存在しないキーにアクセスするたびに同じ1つの配列オブジェクトを返します。その配列を<<で変更すると、まだ触っていないはずの他のキーの値まで変わってしまいます。
- gsub! は置換が発生しないと nil を返す(gsub との違い)破壊的メソッドのgsub!やsub!は、置換対象が見つかって実際に変更が起きた場合は変更後の文字列を、何も置換されなかった場合はnilを返します。戻り値をそのまま次のメソッドにつなげると、置換が起きなかった入力でNoMethodErrorになります。
- 引数なしの rescue は StandardError の子孫しか捕まえないクラス名を指定しない rescue は、暗黙のうちに StandardError とそのサブクラスだけを捕まえます。自作の例外クラスを Exception を直接継承させて定義すると、rescue で捕まえられずプログラムが止まります。
- 必須キーワード引数を渡し忘れると ArgumentError になるデフォルト値の無いキーワード引数(name: のようにコロンだけで値を書かない形)は必須です。呼び出し時に渡し忘れると、通常の引数と同じくArgumentErrorになります。
- private メソッドをレシーバ付きで呼ぶと NoMethodError になるprivateを付けたメソッドは、クラスの外からinstance.methodのようにレシーバを明示して呼び出すことができません。呼び出したい場合は、内部でそのメソッドを使うpublicなメソッド経由にする必要があります。
- each で配列を回しながら delete すると要素が飛ばされるeachで配列を反復しながらdelete_atやdeleteで要素を取り除くと、後続の要素が前に詰まってインデックスがずれ、次に処理されるはずだった要素が読み飛ばされます。
- attr_writer だけでは値を読み出せない(attr_accessor との違い)attr_writerは代入用のメソッド(name=)だけを定義し、読み出し用のメソッド(name)は定義しません。値を読み書き両方したい場合はattr_accessorを使う必要があります。
- 初期化前のインスタンス変数を参照すると警告なしで nil になるinitializeで値を設定し忘れたインスタンス変数は、エラーにも警告にもならず単にnilとして扱われます。存在しないローカル変数がNameErrorになるのとは対照的です。
- シンボルキーのハッシュを文字列キーで参照すると nil になる:name(シンボル)と"name"(文字列)は別のオブジェクトとして扱われるため、シンボルキーで作ったハッシュを文字列キーで参照すると見つからずnilが返ります。
- Comparable を include しても <=> が無いと比較演算子は使えないComparableモジュールをincludeするだけでは <、>、between? などのメソッドは動きません。これらのメソッドは内部で<=>(UFO演算子)を呼び出す仕組みなので、クラス自身に<=>を定義しておく必要があります。
- case文で該当するwhenが無いとnilが返るcase式はいずれのwhenにも一致しない場合、elseが無ければ例外を出さずnilを返します。switch文がエラーになる言語の感覚のままだと、この静かなnilに気づけません。