Ruby 3.2 アドベントカレンダーの10日目の記事です。
Data
Feature #16122: Data: simple immutable value object - Ruby master - Ruby Issue Tracking System
Ruby 3.2 で Data
クラスが新設された。Struct
とほぼ同じなんだけどオブジェクト作った後に値を変更することができない。
Data
をそのまま使うんじゃなくて、Data.define
で Data
の子クラスを作って使う。
Hoge = Data.define(:name, :value) hoge = Hoge.new('abc', 123) #=> #<data Hoge name="abc", value=123> Hoge.new(name: 'abc', value: 123) # これでも同じ Hoge['abc', 123] # これでも同じ hoge.name #=> "abc" hoge.value #=> 123 hoge.name = 'xyz' #=> undefined method `name=' for #<data Hoge name="abc", value=123> (NoMethodError)
Struct
は Struct.new
で子クラスを作ったんだけど、字面的に new
はイマイチじゃない?ってことで Data.define
になったらしい。
なお、Data.new
は NoMethodError になる。
Struct
Struct.new
で構造体クラスを作成できる。
Hoge = Struct.new(:abc, :xyz) hoge = Hoge.new(123, 456) hoge.abc #=> 123 hoge.xyz #=> 456
このようにして作成されたクラスは Ruby 3.1 ではキーワード引数では初期化できない。Hash として第1引数に設定される。warning も出る。
hoge = Hoge.new(abc: 123, xyz: 456) #=> warning: Passing only keyword arguments to Struct#initialize will behave differently from Ruby 3.2. Please use a Hash literal like .new({k: v}) instead of .new(k: v). hoge.abc #=> {:abc=>123, :xyz=>456} hoge.xyz #=> nil
Struct.new
に keyword_init
を指定するとキーワード引数で初期化できるクラスを作成する。ただし位置引数では指定できない。
Hoge = Struct.new(:abc, :xyz, keyword_init: true) hoge = Hoge.new(abc: 123, xyz: 456) hoge.abc #=> 123 hoge.xyz #=> 456 hoge = Hoge.new(123, 456) #=> wrong number of arguments (given 2, expected 0) (ArgumentError)
Ruby 3.2 から keyword_init
を指定しなくてもよくなった。位置引数でもキーワード引数でもどちらでも初期化できる。
Hoge = Struct.new(:abc, :xyz) Hoge.new(123, 456) #=> #<struct Hoge abc=123, xyz=456> Hoge.new(abc: 123, xyz: 456) #=> #<struct Hoge abc=123, xyz=456>
たぶん新しく作られた Data に合わせたのかな。便利。