読者です 読者をやめる 読者になる 読者になる

production.log

ピクスタ株式会社でエンジニアのマネージャーをやっている星直史のブログです。

Rubyで使われるコロンの意味を調べてみた

概要

Rubyを初めて触ったときに、(当時の自分が触っていた)C#JAVAではコロンが使われておらず、 これはどのような意味なのかがよく話からたかったので、まとめてみました。

:symbol
"symbol"

こちらの違いについてまとめます。

Rubyにおけるコロンの意味とは?

Rubyにおけるコロンは、シンボルといいます。

:symbol 一見文字列と同種に見えるが、内部的には数値として扱われます。 そのため、比較や検索などの速度面が文字列と比べると高速になります。

  • ハッシュのキー
  • メソッドの引数として渡すクラス名、メソッド名、変数名、定数名

などについては、はシンボルを使用したほうが良いでしょう。

リファレンスでは

リファレンスを引用します。

Rubyの内部実装では、メソッド名や変数名、定数名、クラス名など の'名前'を整数で管理しています。これは名前を直接文字列として処理するよりも 速度面で有利だからです。そしてその整数をRubyのコード上で表現したものがシンボルです。 シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。 名前を管理するという役割上、シンボルと文字列は一対一に対応します。 また、文字列と違い、immutable (変更不可)であり、同値ならば必ず同一です。

文字列と見せかけて、内部の実装では整数として扱っている。といったところでしょうか。

検証してみた

> Rubyの内部実装では、メソッド名や変数名、定数名、クラス名など の'名前'を整数で管理しています。

つまり、メソッド名や変数名、定数名、クラス名を定義した瞬間にシンボルができるという意味です。 実際にやってみましょう。

class SymbolTest
end

symbol_var = 0

SYMLBOL_CONSTANT = 0

def symbol_method
end

p Symbol.all_symbols.include?(:SymbolTest)
=> true

p Symbol.all_symbols.include?(:symbol_method)
=> true

p Symbol.all_symbols.include?(:symbol_var)
=> true

p Symbol.all_symbols.include?(:SYMLBOL_CONSTANT)
=> true

見事に全てtrueを返しましたね。

> これは名前を直接文字列として処理するよりも 速度面で有利だからです。

文字列と数値なので、そりゃ高速になるだろうと反射的に思いましたが、こちらも検証してみます。

benchmarkというモジュールを使用して計測してみます。 実際のやり方はこちらを参考にしました。 Ruby でベンチマークを取る方法 - Qiita

require 'benchmark'

Benchmark.bm 10 do |r| 
  str = "0123456789"
  str_hash = { "0123456789" => 1 }
  r.report "String" do
    9999999.times { str_hash[str] }
  end 

  sym = :"0123456789"
  sym_hash = { "0123456789" =>  1 }
  r.report "Symbol" do
    9999999.times { sym_hash[sym] }
  end 
end

                 user     system      total        real
String       1.190000   0.000000   1.190000 (  1.190577)
Symbol       0.810000   0.000000   0.810000 (  0.815450)

文字列に比べて、シンボルは30%前後早くなっていますね。 すごいぞシンボル。

> 名前を管理するという役割上、シンボルと文字列は一対一に対応します。 また、文字列と違い、immutable (変更不可)であり、同値ならば必ず同一です。

同じ名前のシンボルであれば、いくつ生成してもオブジェクトIDが1つという意味ですかね。

hoge1 = "hoge"
hoge2 = "hoge"
puts hoge1.equal?(hoge2)
=> false

puts hoge1.object_id
=> 70281989413340

puts hoge2.object_id
=> 70281989361520

sym1 = :hoge
sym2 = :hoge
puts sym1.equal?(sym2)
=> true

puts sym1.object_id
=> 539048

puts sym2.object_id
=> 539048

こちらもリファレンス通りですね。

まとめ

冒頭でも書きましたが、Rubyにおけるコロンは、"シンボル"と呼びます。 一見文字列と同じように見えますが、内部的には整数と同様に扱われます。 そのため

  • 文字列と比較すると処理が高速
  • 同じ値であれば、生成されるオブジェクトは1つ。

また、クラス、メソッド、変数、定数を定義すると、その名前のシンボルも生成されます。

文字列とシンボルの使い分けとしては、

  • ハッシュのキー
  • メソッドの引数として渡すクラス名、メソッド名、変数名、定数名

などは、文字列ではなく、シンボルを使用したほうが良いでしょう。

こちらの本はRubyについて、今でもリファレンス的に使用している本なので、オススメします。
※今回のシンボルについては、ここまで詳細には書かれていませんが、全範囲を網羅的に書かれています。