StructとOpenStruct

似た名前だが意外と挙動が異なるな、と思ったのでメモ。

Struct

# クラスをつくる
> Man = Struct.new(:age, :sex)  # => Man
> Man.class  # => Class

# クラスからインスタンスをつくる
> taro = Man.new(28, :male)  # => #<struct Man age=28, sex=:male>
> taro.class  # => Man

# 定義した属性を利用できる
> taro.age += 1
> taro.age  # => 29

# 定義していない属性は利用できない
> taro.job = :engineer  # NoMethodError: undefined method `job=' for #<struct Man age=28, sex=:male>

OpenStruct

# コアライブラリではなく標準ライブラリ
> require 'ostruct'

# newするとシンプルにOpenClassインスタンスが返ってくる
> taro = OpenStruct.new({age: 28, sex: :male})  # => #<OpenStruct age=28, sex=:male>
> taro.class  # => OpenStruct

# 定義した属性を利用できる
> taro.age += 1
> taro.age  # => 28

# 定義していなかった属性も利用できる
> taro.job = :engineer  # => :engineer
> taro.job  # => :engineer

違い

「最初に定義してない属性を利用できる/できない」というのはStruct/OpenStructという名前から想像できたので問題なし。

意外だったのは以下の違い。

  • Struct.newではClassインスタンス(ex. Man)がつくられる => そのクラスからインスタンス(ex. taro)をつくる
    • 最も具体的なオブジェクトを生成するまでに2段階を要する。
    • 普通にクラスを定義している感覚。
  • OpenStruct.newではいきなりOpenStructインスタンスがつくられる
    • 最も具体的なオブジェクトを生成するまでに1段階のみ要する。
    • クラス定義というよりは、ハッシュを生成している感覚。
    • (Hashとの最大の違いは、メソッドをもたせられることかな?たぶん)