Aqutras Members' Blog

株式会社アキュトラスのメンバーが、技術情報などを楽しく書いています。

Rubyのハッシュ記法について

こんにちは。taniyuです。

今回は、rubyのハッシュ記法について簡単に説明します。

ハッシュの記法

rubyでは、ハッシュの宣言は、{ "hoge" => "hogehoge" } のように、=>(ハッシュロケット)を使って書くことができます。 ruby 1.9以降では、ハッシュは、 { hoge: "hogehoge"} という風に書くことができるようにもなっています。
また、2.2 からは、 {">": "hogehoge"} のように書くことができ、様々な文字が扱えるようになりました。

# いつもの
{"hoge" => "hogehoge"}
# 1.9 以降
{hoge: "hogehoge"}
# 2.2 以降(様々な文字がキーとして使える)
{">": "hogehoge"}

=>(ハッシュロケット)と:(コロン)で何が違うのか

先ほど説明したように、ハッシュの書き方では、=>を使う方法と:を使う方法があります。
この2つの書き方には、どんな違いがあるのか?
それは、文字列とシンボルの違いです。

シンボルについて

シンボルは、任意の文字列と一対一で対応する数値のようなものです。
Rubyでは、メソッド名やクラス名などを整数で管理しています。この整数をRubyのコード上で表現したものがシンボルだそうです。
なので、シンボルは常に同じものを指します。
ちなみに、 任意の文字列をシンボルに変換する場合、to_sym とか intern を使うことで変換できます。

実例

"hoge" と :hoge を5回宣言した際のobject_idを見てみます。

[1] pry(main)> 5.times { puts "hoge".object_id }
70337488946780
70337488946680
70337488946600
70337488946500
70337488946400
[2] pry(main)> 5.times { puts :hoge.object_id }
2336028
2336028
2336028
2336028
2336028

このように、シンボルを利用した書き方の場合、常にobject_idが同じになっています。 これより、任意の文字列に対して、常に同じ数値が割り当てられていることが分かります。

シンボルを使うと何が良いのか

実例の部分で示したように、シンボルの場合、常に同じオブジェクトに参照するため、 メモリ使用量が、文字列よりも少なくなります。また、ハッシュの場合、実効速度が文字列をキーとして 指定する場合よりも速くなるそうです。

まとめ

シンボルは、文字列に一つの数値を対応付けて扱うようなものです。
これにより、無駄なオブジェクトの生成を防ぐことができ、 効率が良くなります。なので、ハッシュを使う際には、シンボルを使った書き方を利用しましょう。

雑談

その1

シンボルと文字列は異なるものなので、以下の様な、一見すると変な書き方もできます。

[1] pry(main)> test = {"hoge" => "hoge1", hoge: "hoge2"}
[2] pry(main)> test["hoge"]
=> "hoge1"
[3] pry(main)> test[:hoge]
=> "hoge2"

ちなみに、rails の params については、 params['hoge'] でも params[:hoge] でも同じ値に、 参照することができます。これは、 ActiveSupport::HashWithIndifferentAccessが利用されているからです。

その2

シンボルは裏側では、

  • シンボルの情報を記録するテーブル
  • そのテーブルの要素を指し示すポインタ

の2つにより実装されていて、テーブルに記録された情報はプログラムが動いている間は保持し続けられます。 このため、Webアプリケーションのようにずっと動かし続けるプログラムの場合、 ユーザからの入力を to_syminternでシンボルに変換するような実装をすると、DoSに弱くなるという問題がありました。

しかし、2.2から、シンボルGCが導入され、そのような問題に対して、対策がなされているみたいです。
参考: (翻訳) Ruby 2.2 のシンボル GC | FIVETEESIXONE

参考

今回は以下のサイトを参考にさせていただきました。ありがとうございます。