rubyライブラリのStructを理解する

2022.06.01

effective ruby 項目10の『構造化データの表現にはHashではなくStructを使おう』のアウトプット

そもそもhashとは

hashとは汎用データ構造である。拡張性があるので非常に便利で使い勝手が良い。キー/値ペアの操作をするときに使う事が多い。

hashの問題点

処理の途中でプロパティを追加できるので中身が把握しずらくなる可能性がある。

animal = { name: "ぽち", age: 4}
animal = { a: "aaa"}
puts animal[:a]
>>> aaa

存在しないプロパティを呼んだ場合でもnilが返ってくるので処理の不備に気付きにくくなる。

animal = { name: "ぽち", age: 4}
puts animal[:a]
>>> 
nilが返ってくるのでエラーにならない

Structとは

動的にクラスを生成できるrubyの標準ライブラリ。

クラス生成時にプロパティを設定できるので途中で中身の把握がしやすい。

animal = Struct.new(:name, :age)
cat = animal.new("ぽち", 4)
puts cat.name
>>> ぽち
ゲッターメソッドとして呼び出せるようになっている。

animal = Struct.new(:name, :age)
cat = animal.new("ぽち", 4)
puts cat.a
>>> undefined method `a' for #<struct name="ぽち", age=4> (NoMethodError)
属性名が正しくない場合はNoMethodErrorになる

また以下のようにブロックにしてメソッドを定義できる

animal = Struct.new(:name, :age) do
  def age_group
    if age <= 18
      "未成年"
    else if age <= 65
      "働きアリ"
    else 
      "シニア"
    end
  end
end
cat = animal.new("ぽち", 4)
puts cat.age_group
>>> 未成年

keyword_init: trueを指定するとキーワード引数で渡せる。bool値で設定、デフォルトはnil。

animal = Struct.new(:name, :age, keyword_init: true)
cat = animal.new("ぽち", 4)
dog = animal.new(age: 5, name: "きなこ")
fox = animal.new(age: 7)
puts cat
puts dog
puts fox
>>> wrong number of arguments (given 2, expected 0) (ArgumentError)
>>> #<struct name="きなこ", age=5>
>>> #<struct name=nil, age=7>
値だけの場合は引数エラーに。キーワード引数と値がない場合はnil。

使い分けるポイント

Structを使うべきところはデータ構造体の拡張性がないところ、もしくは拡張されない堅牢なデータ構造体を用意したい時。

逆に途中の処理結果によってプロパティが追加など拡張されるようなデータ構造体の場合は汎用性があるhashを使うべき。Structで実装すると全てのプロパティを用意しておかなければいけなくなる。

データ構造体の仕様を理解した上でどちらを使うか判断していく。