RubyとC言語における文字列リテラルの違い

こちらのブログ(TECS 開発ブログ ruby のシンボルと文字列)で触れられているrubyのシンボルと文字列の違いについでですが、私はRubyとC言語における文字列リテラルの扱いの違いの影響の方が大きいのではないかと思います。

C言語で

char *a = “ABCEDFG”;

char *b= “ABCEDFG”;

とかくと、「AGCDEFG」がstaticな領域に取られて、aとbが同じアドレスを指すようになります。

#C言語の規格を見ていないので、正確ではないかもしれません。同じなドレスをさすことが多いとしておきます。

しかし、Rubyの場合、単に”ABCDEFG”とすると、これはString.new(“ABCDEFG”)と同じことであり、”ABCDEFG”という文字列を持つStringクラスのインスタンスを生成することになります。

p “ABCDEFG”.object_id

p “ABCDEFG”.object_id

と2回書くと、それぞれ異なる値のオブジェクトIDを返します。

最初に書いたC言語の書き方に近いことをRubyで実現するには、シンボルリテラルを使います。

p :ABCEDFG.to_sym

p :ABCEDFG.to_sym

こちらは、同じシンボルリテラルならば常に同じSymbolオブジェクトを指します。

ただし、Symbolオブジェクトは一致するかしないかぐらいしか比較する手段がありません。

#Ruby 1.9ではメソッドが増えているので事情は違っていますが。

Symbolオブジェクトに対して文字列長の大小の比較とか、アルファベット順のソートなどは出来ません

その点から言うと、文字列というよりはC言語でいうポインタとか配列の添え字を用いた比較に近いです。

C言語でもポインタの値自体の大小比較とか、ソートなどは極めて限定された状況でないと意味のある結果は得られません。

Rubyの中でもSymbolクラスは特殊です。

特筆すべきは、Symbol.newはNoMethodErrorになることです。

Symbolオブジェクトを作るには、シンボルリテラルを記述するかStringクラスのto_symメソッド、internメソッドを用います。

SymbolオブジェクトとStringオブジェクトは1対1対応しています。

またそれぞれのクラスにto_str, to_symが定義されています。

したがって、SymbolオブジェクトとStringオブジェクトの間で同値姓をチェックしたいならば、いったんどちらかに変換してから==で比較するという方法を取ることはできます。

# 本来は、比較する対象があいまいにならないようにするべきでしょうが。

これは私見ですが、Rubyで文字列リテラルが毎回異なるStringオブジェクトを生成すること自体を知らない人の方が多いのではないでしょうか。

もっというと、Stringクラスの非破壊的メソッドを使っているのに、「文字列が変更されていない。おかしい!」という質問がくることの方が多いです。

メソッドの返値が新たに生成されたオブジェクトであることを気にしなくても、Rubyプログラミングは出来てしまう、というか、トレードオフとして「安全である」と強調されます。

多分、Symbolがあることを知らない人の方が多いのでは。

また、初級者のレベルでは、「何故Symbolを使う必要があるか分からない」はずです。

結局、Symbolを使おうという人は、Ruby使いの中では明らかに初心者ではないです。

(上級者でない)多くの人にとって、Symbolは知らないし、知っても、使い道が分からない、有難味が分からないがため、使わないのが現状ではないでしょうか。

#ライブラリとか、フレームワークをつくる側になると、無視できない無駄に感じるようになると思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です