【Ruby】Symbol is 何
おはようございます、こんにちは、こんばんは。
スペースマーケットでWebエンジニアをしています、s0arです。
松屋のチゲ、うまい
社内で「結局Symbolってなんなの?」っていう会話をしました。
ふわっとした回答しかできませんでした。
次話すときには、計算通り、完璧〜に話せるようになろうと思いました。
※注: この記事は公式ドキュメントを読んで知識の整理・補足をするものです。真新しい内容はございませんのでご了承くださいませ。
Symbolさんの公式設定
実装
シンボルを表すクラス。
:this_is_symbol.class
=> Symbol
はい
シンボルは任意の文字列と一対一に対応するオブジェクトです。
文字列の代わりに用いることもできますが、必ずしも文字列と同じ振る舞いをするわけではありません。同じ内容のシンボルはかならず同一のオブジェクトです。
symbol_taro = :taro
=> :taro
# 命名アホすぎて草
symbol_jiro_no_ani = :taro
=> :taro
symbol_taro.object_id
=> 19073628
symbol_jiro_no_ani.object_id
=> 19073628
immutableですよ、全部おんなじオブジェクトですよって話。
生成されたシンボルの一覧は Symbol.all_symbols で得られます。
はえ〜しらんかった
Rubyの内部実装では、メソッド名や変数名、定数名、クラス名などの
名前
を整数で管理しています。これは名前を直接文字列として処理するよりも速度面で有利だからです。そしてその整数をRubyのコード上で表現したものがシンボルです。
メソッド名や変数名、定数名、クラス名などの名前
は内部的にはシンボルですってことやねたぶん
シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。
Rubyの内部実装ようわからんけどポインタとアドレスみたいなもんか
用途
実用面では、シンボルは文字の意味を明確にします。`名前'を指し示す時など、文字列そのものが必要なわけではない時に用います。
- ハッシュのキー { :key => "value" }
- アクセサの引数で渡すインスタンス変数名 attr_reader :name
- メソッド引数で渡すメソッド名 __send__ :to_s
- C の enum 的な使用 (値そのものは無視してよい場合)
ハッシュのキーはよく使うよね。
メソッド引数で渡すメソッド名 __send__ :to_s
BaseObject#__send__
は引数に渡すメソッド名をSymbolまたは文字列で指定できるんですよね。どっちがええの?
せっかくだから俺はこのBaseObject#__send__
の実装を読むぜ!
BasicObject#__send__
の定義部分
__send__
の内部実装呼び出し
文字列からSymbolへの変換処理呼び出し
てなわけで、文字列からSymbolに変換する処理が入っているので、素直にSymbolで渡すのが良さそう。
send以外のメソッド名とか変数名をSymbol or 文字列で渡す系のメソッド(パッとと思いつかないけど)でも、内部的にはこれをやってそうなので基本的にSymbolを渡すのが良さそう。
GC
内部的にシンボルは
- シンボルの情報を記録するテーブル
- そのテーブルの要素を指し示すポインタ
の2つにより実装されています。そのため同じシンボル(同じ文字列から作られたシンボル)を複製しても同じ要素へのポインタが使われるだけなのでメモリ使用量は普通の文字列と比べて少ないです。
# Symbol
symbol_taro = :taro
=> :taro
# 命名アホすぎて草
symbol_jiro_no_ani = :taro
=> :taro
symbol_taro.object_id
=> 19073628
symbol_jiro_no_ani.object_id
=> 19073628
# symbol_taroとsymbol_jiro_no_aniは同じオブジェクト
# 文字列
string_taro = "taro"
=> "taro"
# アホ命名
string_jiro_no_ani = "taro"
=> "taro"
string_taro.object_id
=> 2771582720
string_jiro_no_ani.object_id
=> 2243807940
# string_taroと別オブジェクトになってる
2.2.0 以降においては、テーブルに記録された情報は Ruby によって GC されます。すなわち、ある使わなくなったシンボルのテーブル上の情報はGCによって削除されます。
2.1 以前ではこの機能がなかったため、ユーザからの入力をシンボルに変換するようなプログラムは DoS に対して弱い可能性がありましたが、そのような問題は2.2以降では解決されました。
テーブルに積むだけ積んで消えないからメモリがパンパンになってたんやね
Symbol完全に理解した
今までふんわりした理解だったわけですが、これで完全に理解しました。
これで次に聞かれたときには完璧に答えられますね(たぶん)
というか聞かれたらこの記事読んでもらえばいいや
ふんわり理解はよくない、改めて実感した年の瀬でした。

スペースを簡単に貸し借りできるサービス「スペースマーケット」のエンジニアによる公式ブログです。 弊社採用技術スタックはこちら -> whatweuse.dev/company/spacemarket
Discussion