Movatterモバイル変換


[0]ホーム

URL:


rochefort's blog

この広告は、90日以上更新していないブログに表示しています。

Effective Ruby: 定数がミュータブルなことに注意しよう

良書やなEffectiveRuby

項目4 定数がミュータブルなことに注意しよう

定数のfreeze

moduleDefaultsNETWORKS = ["192.168.1","192.168.2"].freezeenddefhost_addresses(host, networks=Defaults::NETWORKS)  networks.map { |net| net <<".#{host}" }end>> host_addresses(1)=> ["192.168.1.1","192.168.2.1"]>>Defaults::NETWORKS=> ["192.168.1.1","192.168.2.1"]# 書き換えられた!

Arrayのfreezeはハマるやつ。
こう書かないとダメ。

moduleDefaultsNETWORKS = ["192.168.1","192.168.2"].map!(&:freeze).freezeend>> host_addresses(2)Traceback (most recent call last):5: from/Users/rochefort/.anyenv/envs/rbenv/versions/2.5.0/bin/irb:11:in`<main>'        4: from (irb):12        3: from (irb):9:in`host_addresses'        2: from (irb):9:in `map'1: from (irb):9:in`block in host_addresses'FrozenError (can't modify frozen String)

再代入禁止

以下は、書籍とは異なりますが、こっちの方がわかりやすいと思ったので、Defaults::NETWORKS を例にして見ました。

>>Defaults::NETWORKS=> ["192.168.1","192.168.2"]>>Defaults::NETWORKS ="a"(irb):32:warning: already initialized constantDefaults::NETWORKS(irb):3:warning: previous definition ofNETWORKS was here=>"a"# 再代入できた!

というようにwarningは出るが書き換わります。

これを防ぎたければ、module/class自体をfreezeすれば良い。

>>Defaults.freeze=>Defaults>>Defaults::NETWORKS=> ["192.168.1","192.168.2"]>>Defaults::NETWORKS ="a"Traceback (most recent call last):2: from/Users/trsw/.anyenv/envs/rbenv/versions/2.5.0/bin/irb:11:in`<main>'        1: from (irb):39FrozenError (can't modify frozen Module)

余談

このmodule/classでfreezeさせるのは使ったことなかったけど、これを利用しちゃえばArray#map!(&:freeze).freeze という書き方なんてしなくても済むのか。

moduleDefaultsNETWORKS = ["192.168.1","192.168.2"]endDefaults.freezedefhost_addresses(host, networks=Defaults::NETWORKS)  networks.map { |net| net <<".#{host}" }end>> host_addresses(3)Traceback (most recent call last):5: from/Users/rochefort/.anyenv/envs/rbenv/versions/2.5.0/bin/irb:11:in`<main>'        4: from (irb):58        3: from (irb):55:in`host_addresses'        2: from (irb):55:in `map'1: from (irb):55:in`block in host_addresses'FrozenError (can't modify frozen String)

なるほど、これなら定数用のモジュールを用意して、そこでfreezeしちゃえばいいのね。
まぁでも定数って割と限定的なclass内で利用したいケースの方が多い気がするからケースバイケースかなぁ。

覚えておく事項

  • 定数は書き換えられないようにするためにかならずフリーズしよう
  • 定数が配列やハッシュなどのコレクションオブジェクトを参照する場合、コレクションとその要素をフリーズしよう。
  • 既存の定数に新しい値が代入されるのを防ぐためには、定数が定義されているモジュールをフリーズしよう

About
id:rochefortid:rochefort

Ruby・Rails・Mac・Web・Tech、時々日々のことについて書いています。

follow
Search
Top Entries
はてなブックマーク数
Categories
Comments

    引用をストックしました

    引用するにはまずログインしてください

    引用をストックできませんでした。再度お試しください

    限定公開記事のため引用できません。

    読者です読者をやめる読者になる読者になる

    [8]ページ先頭

    ©2009-2025 Movatter.jp