ハッシュやシンボルの理解　[Rubyチェリー本 5章まとめ]

この章ではハッシュやシンボルについて開設されています。
個人的にはこの章は、特に勉強になりました。
知識が深まったと言うよりは、全然知らなかった、と言う感じです。
ポートフォリオ制作では、早く完成させることが一つの目的になっていたので、シンボルの利点の一つである応答時間の速さなど全く気にかけていませんでした。

## ハッシュ

ハッシュとは、**キーと値の組み合わせ**で**データを管理するオブジェクト**のことです。

他の言語では、連想配列やディクショナリ、マップなどと呼ばれている。

```ruby
# 空のハッシュ
{}
# キーと値の組み合わせ
{ キー1 => 値2, キー2 => 値2, キー3 => 値3 }
{ 'japan'=>'yen', 'us'=>'dollar', 'india'=>'rupee' }
```

### 要素の追加・変更・取得

```ruby
# 追加する場合（既にキーが存在している場合は上書きされる）
ハッシュ[キー] = 値
currencies = { 'japan'=>'yen', 'us'=>'dollar', 'india'=>'rupee' }
currencies['italy'] = 'euro'
currencies #=> { 'japan'=>'yen', 'us'=>'dollar', 'india'=>'rupee', 'italy'=>'euro' }
========================
# ハッシュから値を取り出す
ハッシュ[キー]
currencies['us'] #=> 'doller'
```

### ハッシュを使った繰り返し処理

```ruby
currencies = { 'japan'=>'yen', 'us'=>'dollar', 'india'=>'rupee' }

# ブロック引数が2つの場合
currencies.each do |key, value|
	puts "#{key}は#{value}"
end
========================# ブロック引数が1つの場合
currencies.each do |key_value|
	puts "#{key_value[0]}は#{key_value[1]}"
end
========================
#=> japanはyen
#　usはdoller
# indiaはrupee
```

### ハッシュの要素の削除

```ruby
currencies = { 'japan'=>'yen', 'us'=>'dollar', 'india'=>'rupee' }

# deleteメソッドで削除したい要素のキーを指定、戻り値は削除された要素の値
currencies.delete('japan') #=> 'yen'
currencies = { 'us'=>'dollar', 'india'=>'rupee' }
========================
# 削除したい要素のキーがみつからない場合はnilが返る
currencies.delete('italy') #=> nil
currencies = { 'japan'=>'yen', 'us'=>'dollar', 'india'=>'rupee' }
========================
# ブロックを渡すとキーが見つからないときの戻り値を作成できる
currencies.delete('italy') { |key| "Not found: #{key}" }
#=> "Not found italy"
```

## シンボル

ハッシュのキーにはシンボルが利用されることが多い。ここではその理由を説明する。ここはとても勉強になった。

> シンボルを表すクラス。シンボルは任意の文字列と一対一に対応するオブジェクトです。文字列の代わりに用いることもできますが、必ずしも文字列と同じ振る舞いをするわけではありません。同じ内容のシンボルはかならず同一のオブジェクトです。

https://docs.ruby-lang.org/ja/latest/class/Symbol.html

シンボルはコロンに続けて任意の名前を定義する（ハッシュリテラル）。

```ruby
:シンボルの名前
:apple # など
```

### シンボルと文字列の違い

#### 1. クラスの違い。

```ruby
:apple.class #=> Symbol
"apple".class #=> String
```

#### 2. シンボルの中身は整数として管理される

表面的には文字列ではあるが、中身は整数として管理される。
その為、2つの値が同じかどうか調べる場合は、文字列よりも**高速に処理できる**。

#### 3. 同じシンボルであれば、同じオブジェクト

大量の文字列と大量のシンボルでは、シンボルの方がメモリ効率が良くなる。

```ruby
# シンボルだから同じ
:apple.object_id #=>1143388
:apple.object_id #=>1143388
:apple.object_id #=>1143388
# 文字列は異なるID
'apple'.object_id #=>70223819213380
'apple'.object_id #=>70223819233120
'apple'.object_id #=>70223819227780
```

つまりシンボルはイミュータブルオブジェクト。「何かに名前を付けたい、名前なので誰かに勝手に変更されては困る」と言う時にうってつけ。

### シンボルの主な特徴まとめ

1. 表面上は文字列っぽい　→意味がわかりやすい
2. 内部は整数　→高速に値比較できる
3. 同じシンボルは同じオブジェクト　→メモリ使用効率◎
4. イミュータブルオブジェクト　→勝手に変更されることはない

### メソッドのキーワード引数とハッシュ

メソッドに引数を渡す時に、それぞれの引数がどんな意味を持つのか分かりづらい時がある。

```ruby
def buy_burger(menu, drink, potato)
	# ハンバーガーを購入
	if drink
		# ドリンクを購入
	end
	if potato
		# ポテトを購入
	end
end

# チーズバーガーとドリンクとポテトの場合
buy_burger('cheese', true, true)
# チーズバーガーとドリンクの場合
buy_burger('fish', true, false)
```

下記のコードだけでは、何がこのメソッドによって起きているか理解しづらい。

```ruby
buy_burger('cheese', true, true)
buy_burger('fish', true, false)
```

このような場合に可読性の向上を図るのが、メソッドの**キーワード引数**。

```ruby
def メソッド名(キーワード引数1:デフォルト値1, キーワード引数2:デフォルト値2)
	#メソッドの実装
end
```

先程のメソッドの場合には、以下のように適用することができる。

これにより引数の役割が明確になる。

```ruby
def buy_burger(menu, drink: true, potato: true)
	:
end

buy_burger('cheese', drink: true, potato: true)
buy_burger('fish', drink: true, potato: false)
```

またキーワード引数のデフォルト値は省略することも可能。

ただし、この場合には呼び出し時には省略することはできない。

```ruby
def buy_burger(menu, drink:, potato:)
	:
end

buy_burger('fish',potato:false)
#=>　ArgumentError:missingkeywords:drink
```

### **でハッシュを展開

ハッシュリテラル内で他のハッシュのキーと値を展開したい。

```ruby
h = {us:'dollar',india:'rupee'}

#**を付けない場合は構文エラーになる
{japan:'yen',h}
# =>SyntaxError:syntaxerror,unexpected'}',expecting=>
# {japan:'yen',h}

#変数hのキーと値を**で展開させる
{japan:'yen',**h}
#=> {:japan=>"yen",:us=>"dollar",:india=>"rupee"}
```

### 擬似キーワード引数

```ruby
def buy_burger(menu,options={})
	:
end
```

キーワード引数に対する、擬似キーワード引数の特徴

1. メソッドを呼び出す際に、どんなキーを渡してもエラーは発生しない。
2. メソッドの定義内で、ハッシュから値を取り出すコードを追加しなければいけない。

### 任意のキーワードを受け取りたい場合

**をつけた引数を最後に用意する。

```ruby
# othersはハッシュとして渡される。
def buy_burger(menu, drink: true, potato: true, **others)
	:
end
```

またメソッドの呼び出し時には、「最後の引数がハッシュであれば、ハッシュリテラルの{}を省略できる。」という機能がある。