やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

組込ライブラリ(Symbol)

 シンボル。

成果物

情報源

Symbol

シンボルを表すクラス。シンボルは任意の文字列と一対一に対応するオブジェクトです。

 エンドユーザが作る識別子のこと。

文字列の代わりに用いることもできますが、必ずしも文字列と同じ振る舞いをするわけではありません。同じ内容のシンボルはかならず同一のオブジェクトです。

 object_idが一致する。

シンボルオブジェクトは以下のようなリテラルで得られます。

:symbol
:'symbol'
%s!symbol! # %記法

生成されたシンボルの一覧は Symbol.all_symbols で得られます。一番目のリテラルでシンボルを表す場合、:' の後には識別子、メソッド名(!',?',=' などの接尾辞を含む)、変数名 (`$'などの接頭辞を含む)、再定義できる演算子のいずれかに適合するものしか書くことはできません(そうでなければ文法エラーになります)。そうでない文字列をシンボルにしたい場合は残りの表記か String#intern を使用してください。

シンボルの実装と用途

実装

Rubyの内部実装では、メソッド名や変数名、定数名、クラス名などの`名前'を整数で管理しています。これは名前を直接文字列として処理するよりも速度面で有利だからです。そしてその整数をRubyのコード上で表現したものがシンボルです。

 その整数はobject_idのことかな?

シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。

 ユーザは整数でなく文字列を用いて参照できる。そのほうが覚えやすくて便利だから嬉しい。

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

p "abc" == "abc" #=> true
p "abc".equal?("abc") #=> false
p :abc == :abc #=> true
p :abc.equal?(:abc) #=> true ←同値ならば同一

用途

実用面では、シンボルは文字の意味を明確にします。`名前'を指し示す時など、文字列そのものが必要なわけではない時に用います。

  • ハッシュのキー { :key => "value" }
  • アクセサの引数で渡すインスタンス変数名 attr_reader :name
  • メソッド引数で渡すメソッド名 send :to_s
  • C の enum 的な使用 (値そのものは無視してよい場合)

シンボルを使うメリットは

  • 新しく文字列を生成しない分やや効率がよく、比較も高速。
  • 文字の意味がはっきりするのでコードが読みやすくなる
  • immutable なので内容を書き換えられる心配がない

大抵のメソッドはシンボルの代わりに文字列を引数として渡すこともできるようになっています。

Symbol クラスのメソッドには、String クラスのメソッドと同名で似た働きをするものもあります。

GC

内部的にシンボルは

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

の2つにより実装されています。そのため同じシンボル(同じ文字列から作られたシンボル)を複製しても同じ要素へのポインタが使われるだけなのでメモリ使用量は普通の文字列と比べて少ないです。

 文字列だと同じ文字列でも個別にメモリ確保しちゃうってことかな?

2.2.0 以降においては、テーブルに記録された情報は Ruby によって GC されます。すなわち、ある使わなくなったシンボルのテーブル上の情報はGCによって削除されます。

2.1 以前ではこの機能がなかったため、ユーザからの入力をシンボルに変換するようなプログラムは DoS に対して弱い可能性がありましたが、そのような問題は2.2以降では解決されました。

ただし拡張ライブラリ内で rb_intern によって生成されたシンボルに関するテーブル上の情報はGCされませんので注意してください。

メンバ抜粋

特異メソッド

all_symbols

インスタンスメソッド

<=> == =~ [] capitalize casecmp casecmp? downcase empty? encoding end_with? id2name inspect intern length match match? name next size slice start_with? succ swapcase to_proc to_s to_sym upcase
メソッド 概要
capitalize 先頭大文字、以降小文字
downcase 小文字化
swapcase 大小文字切替
upcase 大文字化
メソッド 概要
name freezeされた文字列を返す
to_s,id2name 文字列を返す

all_symbols

p Symbol.all_symbols #=> [:RUBY_PLATFORM, :RUBY_VERSION, ...]

対象環境

$ uname -a
Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux