2008年1月8日火曜日

Ruby のシンボル

1. シンボルの役割

a. シンボルは一意

Ruby で、シンボルを使うと、名前に一意性を持たせることができる。

たのしいRuby (p125) によると、

シンボルとは、Ruby が内部でメソッド名などの識別に使っている数値で、任意の文字列に対して異なった値が割り当てられます。

Emacs Lisp では、タンスの引き出しに例えられている。

 

b. シンボルの書き方

シンボルにはリテラルがあり、接頭辞 `:’ を名前の前につける。

プログラミング言語Ruby — ありえるえりあ のシンボル(3) には、ハッシュのキーをシンボルで書くことが勧められている。

# こうするより
ht1 = { "key1" => "val1", "key2" => "val2" }
# こう書く
ht1 = { :key1 => "val1", :key2 => "val2" }

使い勝手と可読性は文字列と同程度で、実行が速いので、使えるならシンボルを使うこと。

 

c. Symbol クラスのインスタンス

シンボルは、Symbol クラスのインスタンスとして実装されている。

Rubyリファレンスマニュアル - リテラル のシンボルによると、

Symbolクラスのインスタンス。ある文字列とSymbolオブジェクトは一対一に対応します。

文字列にするか、シンボルにするか、いったい何が違うのだ? - ザリガニが見ていた...。 によると、

  • 例えば:actionシンボルは最初に利用した時に、一つのオブジェクトを生成*3して、そのオブジェクトを指し示すマークになる。
  • その後も同一のオブジェクトを指し示すマークであり続ける。
  • シンボルオブジェクトは文字情報を保持していて、その文字情報は不変である。

...

'action'文字列も一つのオブジェクト*4だが、プログラムの中で利用する度に、新たなオブジェクトとして発生する。

 

2. シンボルと文字列の違い

a. 等値性の検査

シンボルは文字列と同じような感覚で用いることができる。ただし、等値性に関して、異なることに注意。

例えば、文字列に対して、 2 つの等値性の検査をするためのメソッド、 ==equal? を試してみる。

  • == は値が等しい場合に真となり、
  • equal? はインスタンスが同じ場合に真となる。
x = "hoge"
y = "hoge"

puts x == y        #=> true
puts x.equal?(y)   #=> false

“○○○” と文字列を生成した場合、値は等しいけれど、インスタンスが異なっていることがわかる。

同じ内容を、シンボルで試してみると、

x2 = :hoge
y2 = :hoge

puts x2 == y2      #=> true
puts x2.equal?(y2) #=> true

文字列の場合と違い、二つは同じインスタンスであり、一意性が担保されている。

 

b. String#intern

String クラスには intern メソッドが定義されている。 intern メソッドの役割は、

文字列に対応するシンボル値(Symbol)を返します

先ほどの文字列の例を使う。

puts x.intern.equal?(y.intern)  #=> true

文字列が、シンボルとして扱われる。

 

c. Java の文字列

Java の場合、== がインスタンスの同一性の検査で、equals が値の等値性の検査。

メソッドの名前的には Ruby と逆。文字列のリテラル

”○○○”

として生成した文字列は、

文字列プールにオブジェクトが作成され

(Java 入門 | 文字列処理 より)

共有される。

 

3. シンボルの利用例

シンボルは、クラスを定義における、メソッドの性質を指定するときに使う。

attr_accessor(name, ... )

属性 name に対する読み込みメソッドと書きこみメソッドの両方を定義します。nameSymbol か文字列で指定します。戻り値は常に nil です。

(Rubyリファレンスマニュアル – Module より)

Rails でもよく見かける。

scaffold :person

(【特選フリーソフト】生産性の高いWeb開発環境 Ruby on Rails:ITpro  より)