ハッシュとシンボル
ハッシュ
ハッシュは基本的には配列と同じですが、整数値以外のインデックス(要素の番号のこと)が使える点と、要素の並び順が保証されない点が配列と異なります。
>> user = {} # {}は空のハッシュ
=> {}
>> user["first_name"] = "Michael" # キーが "first_name" で値が "Michael"
=> "Michael"
>> user["last_name"] = "Hartl" # キーが "last_name" で値が "Hartl"
=> "Hartl"
>> user["first_name"] # 要素へのアクセスは配列の場合と似ている
=> "Michael"
>> user # ハッシュのリテラル表記
=> {"last_name"=>"Hartl", "first_name"=>"Michael"}
ハッシュは、キーと値のペアを波カッコで囲んで表記します。キーと値のペアを持たない波カッコの組({}
)は空のハッシュです。
ここで重要なのは、ハッシュの波カッコは、ブロックの波カッコとはまったく別物であるという点です(これは確かに紛らわしい点です)。ハッシュは配列と似ていますが、1つの重要な違いとして、ハッシュでは要素の「並び順」が保証されないという点があります 。要素の順序が重要である場合は、配列を使う必要があります。
ハッシュの1要素を角カッコを使って定義する代わりに、次のようにキーと値をハッシュロケットと呼ばれる=>
によってリテラル表現するほうが簡単です。
>> user = { "first_name" => "Michael", "last_name" => "Hartl" }
=> {"last_name"=>"Hartl", "first_name"=>"Michael"}
シンボル
ここまではハッシュのキーとして文字列を使っていましたが、Railsでは文字列よりも シンボルを使う方が普通です。シンボルは文字列と似ていますが、クォートで囲む代わりにコロンが前に置かれている点が異なります。例えば:name
はシンボルです。もちろん、余計なことを一切考えずに、シンボルを単なる文字列とみなしても構いません。
ハッシュのキーとしてシンボルを採用する場合、user
のハッシュは次のように定義できます。
>> user = { :name => "Michael Hartl", :email => "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> user[:name] # :name に対応する値にアクセスする
=> "Michael Hartl"
>> user[:password] # 未定義のキーに対応する値にアクセスする
=> nil # 未定義のハッシュ値は単純にnil
シンボルとハッシュロケットの組み合わせを、次のようにキーの名前の「前」ではなく「後」にコロンを置き、その後に値が続くように置き換えられます(h2)。
>> h1 = { :name => "Michael Hartl", :email => "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> h2 = { name: "Michael Hartl", email: "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> h1 == h2
=> true
つまり、
{ :name => "Michael Hartl" }
と{ name: "Michael Hartl" }
というコードは等価になります。
ネストされたハッシュ
ハッシュの値にはほぼ何でも使うことができ、他のハッシュを使うことすらできます。
>> params = {} # 'params' というハッシュを定義する ('parameters' の略)。
=> {}
>> params[:user] = { name: "Michael Hartl", email: "mhartl@example.com" }
=> {:name=>"Michael Hartl", :email=>"mhartl@example.com"}
>> params
=> {:user=>{:name=>"Michael Hartl", :email=>"mhartl@example.com"}}
>> params[:user][:email]
=> "mhartl@example.com"
Railsでは、このようなハッシュのハッシュ(またはネストされたハッシュ)が大量に使われています。
配列や範囲オブジェクトと同様、ハッシュもeach
メソッドに応答します。例えば、:success
と:danger
という2つの状態を持つ flash
という名前のハッシュについて考えてみましょう。
>> flash = { success: "It worked!", danger: "It failed." }
=> {:success=>"It worked!", :danger=>"It failed."}
>> flash.each do |key, value|
?> puts "Key #{key.inspect} has value #{value.inspect}"
>> end
Key :success has value "It worked!"
Key :danger has value "It failed."
ここで、配列のeach
メソッドでは、ブロックの変数は1つだけですが、ハッシュのeach
メソッドでは、ブロックの変数は キーと 値の2つになっていることに注意してください。したがって、 ハッシュに対してeach
メソッドを実行すると、ハッシュ内にある「キーと値のペア」ごとに処理を繰り返します。
最後の例として、便利なinspect
メソッドを紹介します。これは要求されたオブジェクトを表現する文字列を返します。
>> puts (1..5).to_a # 配列を文字列として出力
1
2
3
4
5
>> puts (1..5).to_a.inspect # 配列のリテラルを出力
[1, 2, 3, 4, 5]
>> puts :name, :name.inspect
name
:name
>> puts "It worked!", "It worked!".inspect
It worked!
"It worked!"
ところで、オブジェクトを表示するためにinspect
を使うことは非常に多いので、 p
メソッドというショートカットがあります。
>> p :name # 'puts :name.inspect' と同じ
:name
省略
実は、Ruby では メソッド呼び出しの丸カッコは省略しても構いません。
次の2つのコードは等価です。
> message1 = "Hello"
> message2 = "Thanx"
> message3 = "oraora!"
> message1.concat(message2, message3)
=> "Hello Thanx oraora!"
> message1 = "Hello"
> message2 = "Thanx"
> message3 = "oraora!"
> message1.concat message2, message3 #カッコを省略してメソッド呼び出しを書く
=> "Hello Thanx oraora!"
複雑なコード
次に、少し難しいコードを理解していきます。
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
ここではRailsの組み込み関数stylesheet_link_tag
(引数として指定されたソースのスタイルシート リンク タグを返す)を使ってます。しかし、ここで不思議な点がいくつもあります。第一に、丸カッコがありません。しかし、Rubyではメソッド呼び出しの丸カッコは省略しても構わないので次の2つの行は等価です。
# メソッド呼び出しの丸カッコは省略可能。
stylesheet_link_tag("application", "data-turbo-track": "reload")
# 上は以下のように書いても同じ
stylesheet_link_tag "application", "data-turbo-track": "reload"
したがって、次のコードはstylesheet_link_tagメソッドに引数を2個渡して呼んでいることになります。
次に不思議なのが、2つ目の引数はハッシュのようですが、波カッコがない点です。実は、ハッシュがメソッド呼び出しの 最後の引数である場合は、波カッコを省略できます。次の2つの行は等価です。
# 最後の引数がハッシュの場合、波カッコは省略可能。
stylesheet_link_tag("application", { "data-turbo-track": "reload" })
# 上は以下のように書いても同じ
stylesheet_link_tag("application", "data-turbo-track": "reload")
最初の引数(data-turbo-track
)は、スタイルシートへのパスを指定する文字列です。上のコードは<%= ... %>
で囲まれているので、結果はERBによってビューに挿入されます。