Structって?
rubyに組み込まれてる構造体クラス
http://docs.ruby-lang.org/ja/2.1.0/class/Struct.html
インスタンスを作る際のパターン一覧
結果 | 説明 | |
---|---|---|
Struct.new(:one, :two).new('1', '2') | #<struct one="1", two="2"> | |
Struct.new(:one, :two).new(1, 2) | #<struct one=1, two=2> | 値はintも可 |
Struct.new(:one, :two).new([1, 2], [2, 3]) | #<struct one=[1, 2], two=[2, 3]> | arrayも可 |
Struct.new(:one, :two).new({q: 1, w: 2}, {a: 2, s: 3}) | #<struct one={:q=>1, :w=>2}, two={:a=>2, :s=>3}> | hashも可 |
Struct.new(:one, :two).new({q: 1, w: 2}, [2, 3]) | #<struct one={:q=>1, :w=>2}, two=[2, 3]> | 複合も可 |
Struct.new(:one, :two).new({one: 1, two: 2}) |
#<struct one={:one =>1, :two=>2}, two=nil> |
Hashはあくまでひとつのオブジェクトとして入る |
Struct.new(:one, :two).new(1) | #<struct one=1, two=nil> | メンバの数に対して値の数が足りないときはnilが入る |
Struct.new(:one, :two).new(1, nil) | #<struct one=1, two=nil> | 明確にnilを入れることもできる |
Struct.new(:one, :two).new(1, 2, 3) | ArgumentError: struct size differs | メンバの数より値の数の方が多いときはエラー |
Struct.new('one', 'two').new(1, 2) | NameError: identifier one needs to be constant | メンバの第一引数がStringだったらクラス名にする仕様 先頭が大文字である必要がある |
Struct.new('One', :memb).new('val') | #<struct Struct::One memb="val"> | 先頭大文字のStringだとこうなる |
Struct.new(:one, 'two').new(1, 2) | #<struct one=1, two=2> | ただし一つ目がシンボルなら、 それ以降がStringでもいける |
Struct.new(:one, :two, ['array']).new(1, 2, 3) | TypeError: ["array"] is not a symbol | とはいえ、シンボルに変換できないとダメ |
Struct.new(:true, :false).new(1, 2) | #<struct true=1, false=2> | シンボルであれば何でもいける |
結論①
- メンバはシンボルで指定すべし
- 値の数はシンボルの数と同じにすべし
同じ名前のメンバが存在する場合
basic = Struct.new(:one, :two, :three, :four).new(1, 2, 3, 4)
special = Struct.new(:one, :one, :one, :three).new(1, 2, 3, 4)
上記の2つをレシーバとした結果の違い
basic | special | コメント | |
---|---|---|---|
-- | #<struct one=1, two=2, three=3, four=4> | #<struct one=1, one=1, one=1, four=4> | 最初の値が表示される |
xxx | #<struct one=1, two=2, three=3, four=4> | #<struct one=1, one=1, one=1, four=4> | 最初の戻りと同じ |
xxx.inspect | "#<struct one=1, two=2, three=3, four=4>" | "#<struct one=1, one=2, one=3, four=4>" | 最初の戻りと異なる |
xxx.one | 1 | 3 | 取り出すときは最後の値 |
xxx[:one] | 1 | 1 | |
xxx['one'] | 1 | 1 | |
xxx.members | [:one, :two, :three, :four] | [:one, :one, :one, :four] | |
xxx.values | [1, 2, 3, 4] | [1, 2, 3, 4] | valuesはそのままの値を持っている |
###値を代入してみる
xxx[0] = 10
(xxx.one = 10
とxxx[:one] = 10
も同じ結果)
basic | special | コメント | |
---|---|---|---|
xxx[0] = 10 | 10 | 10 | |
xxx | #<struct one=10, two=2, three=3, four=4> | #<struct one=10, one=10, one=10, four=4> | 0番目以外も修正されて見える |
xxx.inspect | "#<struct one=10, two=2, three=3, four=4>" | "#<struct one=10, one=2, one=3, four=4>" | こっちは0番目しか変わっていない |
xxx[0] | 10 | 10 | |
xxx[1] | 2 | 2 | |
xxx[2] | 3 | 3 | |
xxx[:one] | 10 | 10 | |
xxx['one'] | 10 | 10 | |
xxx.one | 10 | 3 | 変わってない |
xxx.members | [:one, :two, :three, :four] | [:one, :one, :one, :four] | |
xxx.values | [10, 2, 3, 4] | [10, 2, 3, 4] | valuesは想定通り |
結論②
- 同じ名前のメンバは使わない
最終結論
Structを使う場合は
- 要素数を合わせる
- メンバ名はシンボルを使い、ユニークにする
# 無名クラス
Struct.new(:memb1, :memb2).new(val1, val2)
# 名前付き
Struct.new('Name', :memb1, :memb2).new(val1, val2)
色々調べたけど、結局は「普通に使おう」って感じ。