LoginSignup
9
9

More than 5 years have passed since last update.

Structのオキテ

Posted at

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=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 = 10xxx[: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)

色々調べたけど、結局は「普通に使おう」って感じ。

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9