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 に合わせたのかな。便利。