はじめに
条件分岐やループ処理、変数やメソッド(関数)など、プログラミング言語が変わっても「基本的な考え方はだいたいどれも同じ」という概念や機能がある一方、「これは○○というプログラミング言語以外ではあまり見かけない」という、その言語固有の機能もあります。
Rubyに登場する「シンボル(Symbol)」も、そうした「他の言語ではあまり見かけないデータ型(オブジェクト)のひとつ」です。
ただし、シンボルはRubyやRailsのコードで頻繁に登場するため、Rubyを読み書きする際はきちんと理解しておくことが望ましいです。他の言語ではあまり見かけないからといって、その存在を無視するわけにはいきません。
そこでこの記事では、他言語の経験者向けに「Rubyのシンボルとは何か」を易しく解説します。
対象読者、必要な前提知識など
この記事は以下のような読者を想定して執筆しています。
- PythonやJava、JavaScriptなど、Ruby以外のプログラミング言語を使った経験がある人
プログラミング経験者を対象としているので、「変数とは」「条件分岐とは」といったような、プログラミングの基礎知識は説明しません。
また、シンボルを説明の対象にしているため、Rubyの基礎知識もここでは説明しません。必要に応じて最小限の解説は入れますが、易しいコードが中心なので、なんとなく雰囲気で理解してもらう想定です。どうしてもわからないコードがあれば、ネットの情報やChatGPTの回答などを参照してください。
対象バージョン
この記事に登場するRubyのコードはいずれも基礎的なものばかりなので、最近のRuby(Ruby 3.0以上)であればどれも問題なく動くはずです。
それでは以下が本編です!
name: みたいに、コロン(:)が付くアイツは何だ?
Rubyのコードを見ていると、ときどき:が登場します。たとえば、以下のようなコードです。
# name: や age: の ":" って何だろう?
user_data = { name: 'Alice', age: 20 }
name: や age: はシンボル(Symbol)と呼ばれるRubyのオブジェクトです。上の例では「キーと値」の「キー」をシンボルで指定しています。
# キーがname:で値が'Alice'
name: 'Alice'
# キーがage:で値が20
age: 20
つまり、最初のコードは、名前(name:)が'Alice'、年齢(age:)が20のハッシュオブジェクトを生成し、user_dataという変数に代入するコードです。
# 名前(name:)が'Alice'、年齢(age:)が20の
# ハッシュオブジェクトを、user_dataという変数に代入
user_data = { name: 'Alice', age: 20 }
このように、Rubyのシンボルは「キーと値」の「キー」を指定するためによく使われます。
ちなみに、Rubyのハッシュオブジェクトとは、キーで値を管理するコレクションオブジェクトです。他の言語でいうところの連想配列(辞書やマップと呼ばれたりもする)に相当するオブジェクトだと考えてもらえればOKです。
実はコロン(:)は左側に来るのが本来のシンボル記法
ただし、シンボルはそれ自体が独立したオブジェクトなので、123のような数値や、"abc"のような文字列と同じ扱いになります。ですので、シンボルをいったん変数に入れて使うこともできます。
次のコードを見てください。このサンプルコードは最初に見たコード例と同じ動きをします。
# 変数にシンボルを代入
key_1 = :name
key_2 = :age
# 変数経由でキーを指定
user_data = { key_1 => 'Alice', key_2 => 20 }
# 上のコードは最初に見たこのコードと同じ
# user_data = { name: 'Alice', age: 20 }
ですが、「おやっ?」と思う点が2つありますね。ひとつはname:ではなく:nameのように:が左側に来ている点で、もうひとつは=>という見慣れない記号が出てきた点です。
この疑問を解くためのカギは、以下の3つです。
-
:nameのように:が左に来るのが、本来のシンボルの記法である -
キー => 値のように=>を使ってキーと値を指定するのが、本来のハッシュ記法である - ハッシュ記法では、キーがシンボルの場合だけ、シンボルの
:を右に移動し、=>を省略できるという構文上の特例(シンタックスシュガー)がある
ですので、最初に見たコードは、「ハッシュ記法のシンタックスシュガー」を使っていたことになります。
# これが本来のハッシュ記法
user_data = { :name => 'Alice', :age => 20 }
# シンタックスシュガーを使ったコード(上のコードと意味は同じ)
user_data = { name: 'Alice', age: 20 }
一方、シンボルを変数に入れるとこのシンタックスシュガーが使えなくなるため、本来のハッシュ記法で使う=>が登場したのでした。
# 変数をキーとして使っているため、シンタックスシュガーが使えない
user_data = { key_1 => 'Alice', key_2 => 20 }
同様に、key_1 = :nameのように変数代入時に:が左側に来ているのも、これがハッシュ記法と無関係な構文(ただの変数への代入)だからです。
# ハッシュ記法を使っているわけではないので、:の位置は左
key_1 = :name
シンボルはキーの指定以外にも使える
先ほども述べたとおり、シンボルは:が左側に来るのが本来の記法であり、なおかつ独立したオブジェクトです。そのため、シンボルはキーの指定以外にも使えます。
以下はキーの指定以外にシンボルが使われる例です。
# Railsでよく使われるテンプレート指定の一例
# これは「:editページを描画(render)しろ」の意味
render :edit
上のコードではrenderメソッドの引数として、シンボル単体の:editを渡しています(:が左側に来ている点に注目してください)。
文字列とシンボルの違い
ところで、文字列とシンボルはよく似ています。先ほど見たコードは、シンボルではなく文字列を使っても良さそうに見えます。なぜ文字列ではなく、シンボルを使うのでしょうか?1
# :editというシンボルでテンプレートを指定する
render :edit
# 'edit'という文字列でテンプレートを指定する
render 'edit'
上で示した例のように、シンボルと文字列はコード上の見た目はよく似ていますが、内部的には次のような違いがあります。
- 文字列はその都度新しいオブジェクトが作られるが、シンボルは同じシンボルは同じオブジェクトが再利用されるため効率的
- シンボルは内部的に数値として管理されるため、文字列に比べて軽量かつ処理効率がよい
- シンボルは変更不可(イミュータブル)なので、安全性が高い(文字列と違って予期せず変更される心配が無い)
このように、シンボルは「軽くて安全」という特性があるため、ソースコード上では名前を識別したいが、その名前が必ずしも文字列でなくても良い場合によく使われます。
雑にまとめるなら、シンボルは「名札としてよく使われるオブジェクト」という感じでしょうか。
先ほど見たrender :editというコードも、:editは必ずしも文字列である必要はない(:editという名前だけがわかればよい)ため、文字列ではなくシンボル(名札)が使われていたのでした。
おまけ: キーも値もシンボルだとこうなる
ちなみに、キーだけでなく、値もシンボルだった場合に、「ハッシュ記法のシンタックスシュガー」を使うと次のようなコードになります。
# occupation: :engineer の部分がシンタックスシュガー
user_data = { name: 'Alice', age: 20, occupation: :engineer }
キーのシンボルは:が右に来ますが、値のシンボルは:は左に来ます。そのため: :のように、スペース区切りでコロンが連続するコードが発生します。
初めて見たときは「なんだこれ?」とびっくりするかもしれませんが、ここまでに説明した理屈を理解していれば、「キーも値もシンボルが使われているだけ」だとわかるはずです。
まとめ
というわけで、この記事ではRubyのシンボルについて、Ruby未経験者でも理解しやすいように詳しく説明してみました。
Rubyではシンボルがいろんな場面で使われます。しかし、「見た目がなんとなく文字列っぽい」「使われ方も文字列っぽい」という特徴があるため、Ruby初心者は「シンボルっていったい何なんだ!?」と混乱しがちです(というか、筆者がそうでしたw)。
上で説明した通り、Rubyのシンボルは、いわば「文字列よりも軽量で、文字列よりも安全な名札」です。
この先Rubyのコードを読んでいて、name:や:editのように、「コロンが付いた文字列っぽい雰囲気の何か」を見つけたら、この記事の内容を思い出してください!
参考文献
本記事の説明や考え方の一部は、下記の書籍を参考にしています。
-
ちなみに、Railsはシンボルでも文字列でもテンプレートを指定できるように作られています。] ↩