Structのオキテ


## Structって？
rubyに組み込まれてる構造体クラス
http://docs.ruby-lang.org/ja/2.1.0/class/Struct.html


## インスタンスを作る際のパターン一覧

|                                                      | 結果                                                                           | 説明 |
|:---                                                  |:---                                                                            |:---|
|Struct.new(:one, :two).new('1', '2')                  |#&lt;struct one="1", two="2">                                                   ||
|Struct.new(:one, :two).new(1, 2)                      |#&lt;struct one=1, two=2>                                                       |値はintも可|
|Struct.new(:one, :two).new([1, 2], [2, 3])            |#&lt;struct one=[1, 2], two=[2, 3]>                                             |arrayも可|
|Struct.new(:one, :two).new({q: 1, w: 2}, {a: 2, s: 3})|#&lt;struct one={:q=>1, :w=>2}, two={:a=>2, :s=>3}>                             |hashも可|
|Struct.new(:one, :two).new({q: 1, w: 2}, [2, 3])      |#&lt;struct one={:q=>1, :w=>2}, two=[2, 3]>                                     |複合も可|
|Struct.new(:one, :two).new({one: 1, two: 2})          |~~#&lt;struct one=1, two=2>~~ <br> #&lt;struct one={:one =>1, :two=>2}, two=nil>|Hashはあくまでひとつのオブジェクトとして入る|
|Struct.new(:one, :two).new(1)                         |#&lt;struct one=1, two=nil>                                                     |メンバの数に対して値の数が足りないときはnilが入る|
|Struct.new(:one, :two).new(1, nil)                    |#&lt;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                                  |メンバの第一引数がＳtringだったらクラス名にする仕様<br> 先頭が大文字である必要がある|
|Struct.new('One', :memb).new('val')                   |#&lt;struct Struct::One memb="val">                                             |先頭大文字のStringだとこうなる|
|Struct.new(:one, 'two').new(1, 2)                     |#&lt;struct one=1, two=2>                                                       |ただし一つ目がシンボルなら、 <br> それ以降がStringでもいける|
|Struct.new(:one, :two, ['array']).new(1, 2, 3)        |TypeError: ["array"] is not a symbol                                            |とはいえ、シンボルに変換できないとダメ|
|Struct.new(:true, :false).new(1, 2)                   |#&lt;struct true=1, false=2>                                                    |シンボルであれば何でもいける|


### 結論①
+ メンバはシンボルで指定すべし
+ 値の数はシンボルの数と同じにすべし

## 同じ名前のメンバが存在する場合

```ruby
  basic   = Struct.new(:one, :two, :three, :four).new(1, 2, 3, 4)
  special = Struct.new(:one, :one, :one, :three).new(1, 2, 3, 4)
```

### 上記の２つをレシーバとした結果の違い
|           | basic                                      | special                                 | コメント |
|:---       |:---                                        |:---                                     |:---     |
| --        |#&lt;struct one=1, two=2, three=3, four=4>  |#&lt;struct one=1, one=<span style="color: red">1</span>, one=<span style="color: red">1</span>, four=4>  |最初の値が表示される|
|xxx        |#&lt;struct one=1, two=2, three=3, four=4>  |#&lt;struct one=1, one=<span style="color: red">1</span>, one=<span style="color: red">1</span>, four=4>  |最初の戻りと同じ|
|xxx.inspect|"#&lt;struct one=1, two=2, three=3, four=4>"|"#&lt;struct one=1, one=<span style="color: red">2</span>, one=<span style="color: red">3</span>, four=4>"|最初の戻りと異なる|
|xxx.one    |1                                           |<span style="color: red">3</span>                                        |取り出すときは最後の値|
|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はそのままの値を持っている|

###値を代入してみる
```ruby
  xxx[0] = 10
```

（`xxx.one = 10`と`xxx[:one] = 10`も同じ結果）

|           | basic                                        | special                                    | コメント |
|:---       |:---                                          |:---                                        |:---|
|xxx[0] = 10|10                                            |10                                          |
|xxx        |#&lt;struct  one=10, two=2, three=3, four=4>  |#&lt;struct  one=10, one=<span style="color: red">10</span>, one=<span style="color: red">10</span>, four=4>|0番目以外も修正されて見える|
|xxx.inspect|"#&lt;struct  one=10, two=2, three=3, four=4>"|"#&lt;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                                            |<span style="color: red">3</span>                                           |変わってない|
|xxx.members|[:one, :two, :three, :four]                   |[:one, :one, :one, :four]                   ||
|xxx.values |[10, 2, 3, 4]                                 |[10, 2, 3, 4]                               |valuesは想定通り|



### 結論②
+ 同じ名前のメンバは使わない


## 最終結論
Structを使う場合は

+ 要素数を合わせる
+ メンバ名はシンボルを使い、ユニークにする


```ruby
  # 無名クラス
  Struct.new(:memb1, :memb2).new(val1, val2)

  # 名前付き
  Struct.new('Name', :memb1, :memb2).new(val1, val2)
```

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