本記事では、Rubyの文法の中でも特徴的な、
ハッシュとシンボルについて紹介します。
特にシンボルについては、他のプログラミング言語では、
あまり見かけないデータ構造かと思います。
こうしたハッシュとシンボルについての解説と、文字列との違い、
省略記法についても言及します。
本記事の動画は下記になります。
ハッシュ
ハッシュというと、
なんぞやって感じる人が多いと思いますが、
これは要するに、他のプログラミング言語で言う、
辞書とか連想配列みたいなもんで、
{'taro' => 100, 'hanako' => 200}みたいなデータ構造です。
irb(main):001:0> money = {'taro' => 100, 'hanako' => 200}
=> {"taro"=>100, "hanako"=>200}
irb(main):002:0> money
=> {"taro"=>100, "hanako"=>200}
ハッシュもブロックも、
同じ{}で定義するので紛らわしいですね。
要素の取得/追加/変更
要素の追加などは、
配列のときと似ており、
irb(main):004:0> money['takumi'] = 400 #これで追加
=> 400
irb(main):005:0> money
=> {"taro"=>100, "hanako"=>200, "takumi"=>400}
irb(main):006:0> money['taro'] #取得したいキーを指定する
=> 100
irb(main):007:0> money['kyoko'] #存在しないキーならnilを返す
=> nil
といった感じです。
Rubyの配列についての解説は、
こちらの記事をご参考ください。
-
参考【Rubyループ処理】 配列each/map/forやスコープ
本記事では、Rubyの配列とループ処理を扱います。 Rubyには、ブロックという特徴的な文法があり、ループ処理もそれに関連してか、他のプログラミング言語よりもメソッドがたくさんあります。 本記事ではそ ...
続きを見る
キーにシンボルを使う
キーに文字列ではなく、
シンボル(シンボルについては後述)
を使うことのほうがおそらく多いので、
それについても紹介します。
irb(main):026:0> money = { :taro => 100, :hanako => 200 }
=> {:taro=>100, :hanako=>200}
irb(main):027:0> money[:taro]
=> 100
キーがシンボルの場合は、
省略形もあります。
irb(main):028:0> money = { taro: 100, hanako: 200 }
=> {:taro=>100, :hanako=>200}
irb(main):029:0> money
=> {:taro=>100, :hanako=>200}
irb(main):030:0>
=> を使わないで、
シンボル: 値という省略した記法が使えます。
そして、おそらくこの省略された記法が
一番良く使われているかと思います。
メソッド呼び出し時の省略
メソッドの引数の最後がハッシュの場合、
{}を省略できます。
# Railsで見かける例のやつ
stylesheet_link_tag 'application', { media: 'all',
'data-turbolinks-track': 'reload' }
# 上は以下のように書いても同じ
stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload'
def print_hello(greet, options)
puts options
puts greet
end
print_hello('hello', { taro: 100, hanako: 200})
print_hello 'hello', { taro: 100, hanako: 200} #メソッド呼び出しの()は省略できる
print_hello 'hello', taro: 100, hanako: 200 #ハッシュが最後の引数なので{}は省略できる
Rubyは何をするにも
省略記法があるので、
Dryすぎて、逆に混乱してしまうのが悩みです。
シンボル
さて、ハッシュの次は、
シンボルについて触れていきます。
シンボルは、結構Ruby独特のものかなと感じており、
他のプログラミング言語ではあまり見たことがないかもしれません。
class Symbol (Ruby 3.2 リファレンスマニュアル) (ruby-lang.org)
平たく言えば、文字列と似ているものですが、
文字列とも異なるといった感じです。
:hogeのように表します。
irb(main):009:0> :hoge
=> :hoge
irb(main):010:0> :hoge.class
=> Symbol
irb(main):011:0> 'hoge'.class
=> String
シンボルと文字列の違い
そもそもシンボルは、文字列っぽいですが、
内部では整数として扱われているようです。
シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。
名前を管理するという役割上、シンボルと文字列は一対一に対応します。また、文字列と違い、immutable (変更不可)であり、同値ならば必ず同一です。
Ruby 3.2 リファレンスマニュアル
そのため、文字列よりも高速に比較ができるようです。
加えて、シンボルは同じものなら、
同じオブジェクトという特徴があります。
irb(main):012:0> :hoge.object_id
=> 2039708
irb(main):013:0> :hoge.object_id
=> 2039708
irb(main):014:0> :hoge.object_id
=> 2039708
irb(main):015:0> 'hoge'.object_id
=> 180
irb(main):016:0> 'hoge'.object_id
=> 200
irb(main):017:0> 'hoge'.object_id
=> 220
あとは、上記のリファレンスマニュアルにもあったように、
immutable(変更不可)なので、破壊的メソッドなどで書き換えられてしまうという
懸念がないのがメリットかもしれません。
irb(main):018:0> a = 'hoge'
=> "hoge"
irb(main):019:0> b = :hoge
=> :hoge
irb(main):020:0> a.upcase!
=> "HOGE"
irb(main):021:0> a #破壊的メソッドによって書き換わっている
=> "HOGE"
irb(main):022:0> b.upcase! #破壊的メソッドは呼び出せない
Traceback (most recent call last):
4: from /Users/reisuta/.rbenv/versions/2.7.7/bin/irb:23:in `<main>'
3: from /Users/reisuta/.rbenv/versions/2.7.7/bin/irb:23:in `load'
2: from /Users/reisuta/.rbenv/versions/2.7.7/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
1: from (irb):22
NoMethodError (undefined method `upcase!' for :hoge:Symbol)
Did you mean? upcase
もちろん、ケースバイケースではあるのですが、
個人的には文字列とシンボルで迷ったら、
可能な限りシンボルを使ったおくのが好ましいのかなと感じます。
シンボルは、シンプルなようで、
意外と奥が深いので使いこなすのは、
案外難しい印象です。
少しづつ慣れて、使いこなせるようになりたいですね。