Rubyでハッシュを利用する際の文字列とシンボルの違い

プログラミング初心者のため、他サイトを参考にまとめてみる。

テーマはRubyでハッシュを利用する際に文字列利用とシンボル利用の違いである。

 今回のテーマは何度本を読んでも理解できないオブジェクト指向に関連するテーマのように感じるため、本質的な理解は先になりそうだが。。

 

まずは「Ruby シンボル」で検索。下記記事が非常に参考になる。

 

Rubyのシンボルは文字列の皮を被った整数だ!

 

Ruby空間における操作対象(オペランド)はオブジェクトである。Rubyオペレータはオブジェクトしか取り扱わない。オブジェクトはユーザによって初めてRuby空間に生み出されるが、それはクラスという設計図に従って常に構築される。

(中略)

Ruby空間に生み出されたすべてのオブジェクトはそれぞれが固有のID(object_id)を持っていて、RubyオペレータはこのIDで個々のオブジェクトを管理する。

 

相変わらずオブジェクトがなんなのかはよくわからないが、Rubyを書いている時にはオブジェクトしか扱っておらず、全てのオブジェクトはそれぞれ固有のIDを持っているということらしい。

 

次は固有のIDについて調べてみる。

ref.xaio.jp

 

object_idメソッドは、レシーバのオブジェクトIDを返します。オブジェクトIDは、オブジェクトごとに固有の整数値です。レシーバが同じオブジェクトなら必ず同じオブジェクトIDになり、違うオブジェクトなら別のオブジェクトIDが返ります。

str1 = "hello"
puts str1.object_id
str2 = "hello"
puts str2.object_id
10262880
10262528    (実行ごとに結果は変わります)

 

さっきの記事と似たようなことが書いてある。コードを見ると、"str1"と"str2"は同じ文字列"hello"が代入されているが、オブジェクトIDは異なる事がわかる。コンピューターは同じ文字でつでも違うオブジェクトと認識しているようだ。

 

RubyのオブジェクトIDと、ディープ/シャロー(deep/shallow)コピーについて | task blog

 

1
2
1.object_id   #=> 3
'1'.object_id #=> 70183691563540

 ちなみに、'1'とかは、内部的にはString.new('1')をしているのと同じなので、毎回オブジェクトIDが異なります。

ただ1は、オブジェクトIDは変わりません。

赤字の部分を読むと、なんとなくどんな処理を内部で行っているかイメージする事ができる。同じ文字列でも内部的には新たな'1'を生成しているようだ。

 

面白い比較があった。

 

シンボルとは何か その1(後編) - 文字列のintern - 世界線航跡蔵

 

intern操作によって、文字列はオブジェクトとして一意になる。だから、同一性判定するだけで低コストで比較できる。

  1. 10.times do  
  2.   p "foo".object_id  
  3. end  

すると毎回違う結果が出るが、

  1. 10.times do  
  2.   p "foo".intern.object_id  
  3. end  

は同じ結果がずらりと並ぶ。この「文字列をinternした結果」こそがSymbolオブジェクトなのである。

 

最初の記事に戻って結論。

 

Rubyのシンボルは文字列の皮を被った整数だ!

シンボルの特性をまとめてみよう。

  1. 文字列と一対一に対応した記号である(文字列オブジェクトとシンボルオブジェクトは多対一の関係になる)
  2. 同一記号のシンボルはRuby空間に唯一つ存在する(整数と同様、文字列と相違)
  3. シンボル記号自体が意味付けを表象できる(文字列と同様、整数と相違)

これらの特性を考えれば、そのオブジェクトの変更が予定されない場合、無駄なオブジェクトが生成されないシンボルは、速度の点で文字列オブジェクトよりも有利であり、またその記号の可読性を高めたい場合、整数オブジェクトよりも有利である。

 

 文字列を利用する場合は、同じ文字列でも新しいオブジェクトが生成されており、同一記号のシンボルがRuby空間に一つだけのシンボルを利用する際に比較して処理に時間がかかり、かつ管理のしやすさの面でもシンボルの方が有利ということだ。

 

今後も学習を進めながらオブジェクトの概念をつかめるようにしていきたい。