Ruby の変数と定数の種別は変数名の最初の一文字によって、以下のいずれかに区別されます。
- ローカル変数
- インスタンス変数
- クラス変数
- グローバル変数
- 定数
通常の変数の二文字目以降は英数字または
_ ですが、組み込み変数の一部には「$ + 1 文字の記号」という変数があります(組み込み変数を参照)。変数名の長さにはメモリのサイズ以外の制限はありません。
@ などの種別を表す記号も含めた全体が変数名です。名前の本体には
字句構造 の識別子が使えます。ソースエンコーディングが
ASCII 以外の場合、識別子には漢字・仮名などの ASCII 範囲外の文字も広く使えますが、全角スペース(U+3000)のような見た目で区別しにくい文字も識別子の一部になれる点には注意してください。例えば
あ い = 42 は、全角スペースを 1 文字含む名前のローカル変数
あ い への代入として解釈されます。
ローカル変数
ローカル変数として使えるさまざまな識別子foo_bar
_
_foo
ω
ローカル変数の名前は、小文字または _ で始まる識別子です。ローカル変数スコープ(クラス、モジュール、メソッド定義の本体)における小文字で始まる識別子への最初の代入が、そのスコープに属するローカル変数の宣言になります。宣言のための特別な構文はありません。
なお、小文字で始まる識別子の参照は、メソッド呼び出しのこともあります。その識別子がローカル変数として宣言済みならローカル変数の参照、宣言されていなければ引数の無いメソッド呼び出しとみなされます(メソッド呼び出し を参照)。
ローカル変数のスコープは、宣言した位置からその変数が宣言されたブロック、メソッド定義、またはクラス/モジュール定義の終りまでです。寿命もそのブロックの終りまで(トップレベルのローカル変数はプログラムの終了まで)ですが、例外としてブロックが手続きオブジェクト化された場合は、そのオブジェクトが消滅するまで存在します。同じスコープを参照する手続きオブジェクト間ではローカル変数は共有されます。
# (A) の部分はスコープに入らない
2.times do
p defined?(v) # (A)
v = 1 # ここ(宣言開始)から
p v # ここ(ブロックの終り)までが v のスコープ
end
# => nil
# 1
# nil <- これが nil であることに注意
# 1
宣言は、たとえ実行されなくても宣言とみなされます。
v = 1 if false # 代入は行われないが宣言は有効
p defined?(v) # => "local-variable"
p v # => nil
インスタンス変数
例@foobar
@ で始まる変数はインスタンス変数であり、特定のオブジェクトに所属しています。インスタンス変数はそのクラスまたはサブクラスのメソッドから参照できます。
初期化されていないインスタンス変数を参照したときの値は nil です。
クラス変数
例class Foo
@@foo = 1
def bar
puts @@foo
end
end
@@ で始まる変数はクラス変数です。クラス変数はクラス定義の中で定義され、クラスの特異メソッド、インスタンスメソッドなどから参照/代入できます。
クラス変数は定数と以下の点で異なります。
- 再代入可能(定数は警告を出す)
- クラスの外から直接参照できない(継承されたクラスからは参照/代入可能)
クラス変数はクラス自身のインスタンス変数とは以下の点で異なります。
- サブクラスから参照/代入が可能
- インスタンスメソッドから参照/代入が可能
言い換えると、クラス変数は「そのクラスを頂点とする継承ツリーと、そのインスタンス」という範囲の中でならどこからでも参照・代入できる、共有された変数です(プログラム全体から見えるわけではない点がグローバル変数と異なります)。
class Foo
@@foo = 1
end
class Bar < Foo
p @@foo += 1 # => 2
end
class Baz < Bar
p @@foo += 1 # => 3
end
モジュールで定義されたクラス変数(モジュール変数)は、そのモジュールをインクルードしたクラス間でも共有されます。
module Foo
@@foo = 1
end
class Bar
include Foo
p @@foo += 1 # => 2
end
class Baz
include Foo
p @@foo += 1 # => 3
end
親クラスに、子クラスで既に定義されている同名のクラス変数を追加した場合、子クラスが、そのクラス変数を参照した際に例外 RuntimeError が発生します。
class Foo
end
class Bar < Foo
@@v = :bar
end
class Foo
@@v = :foo
end
class Bar
@@v # ~> RuntimeError: class variable @@v of Bar is overtaken by Foo
end
クラス変数のスコープ
クラス変数は、その場所を囲むもっとも内側の(特異クラスでない)クラス定義式またはモジュール定義式のボディをスコープとして持ちます。
クラス定義式にもモジュール定義式にも囲まれていないトップレベルでクラス変数を参照・代入すると、例外 RuntimeError が発生します。
@@foo = 1 # ~> RuntimeError: class variable access from toplevel
class Foo
@@a = :a
class << Foo
p @@a # => :a
end
def Foo.a1
p @@a
end
end
p Foo.a1 # => :a
def Foo.a2
p @@a
end
Foo.a2 # ~> RuntimeError: class variable access from toplevel
class << Foo
p @@a # ~> RuntimeError: class variable access from toplevel
end
グローバル変数
例$foobar
$/
$ で始まる変数はグローバル変数で、プログラムのどこからでも参照できます(その分、利用には注意が必要です)。
グローバル変数には宣言は必要ありません。初期化されていないグローバル変数を参照したときの値は nil です。
組み込み変数
$ で始まる変数のうち、Ruby 処理系によってあらかじめ特殊な意味を与えられているものを組み込み変数と呼びます。
詳細は Kernel の特殊変数を参照してください。
識別子と分類
「特殊変数」「オプション変数」は、いずれも組み込み変数のうち名前に特徴があるものを指す呼び名です。
組み込み変数の一部は、通常の変数としては使用できない特殊な名前を持っています。例えば、$' や $& あるいは $1, $2, $3 がそうです。このように 「$ + 特殊文字一文字」、または「$ + 10進数字列」という名前を持つ組み込み変数を特殊変数と呼びます。
また、$-F や $-I のような変数もあります。これらは Ruby の起動オプション -F や -I などと対応しており、オプション変数と呼ばれます。
スコープ
組み込み変数は文法解析上はグローバル変数として扱われます。しかし、実際のスコープは必ずしもグローバルとは限りません。
組み込み変数には次の種類のスコープがありえます。
- グローバルスコープ
-
通常のグローバル変数と同じ大域的なスコープを持ちます。
- ローカルスコープ
-
通常のローカル変数と同じスコープを持ちます。つまり、クラス定義式本体やメソッド本体で行われた代入はその外側には影響しません。プログラム内のすべての場所において代入を行わずともアクセスできることを除いて、通常のローカル変数と同じです。
- スレッドローカルスコープ
-
スレッドごとの値を持ちます。他のスレッドで異なる値が割り当てられても影響しません。
また、一部の変数は読み取り専用です。ユーザープログラムから変更できません。代入しようとすると実行時に例外を生じます。
擬似変数
通常の変数以外に擬似変数と呼ばれる特殊な変数があります。
self-
現在のメソッドの実行主体。
nil-
NilClassクラスの唯一のインスタンス。 Object#frozen? は
trueを返します。 true-
TrueClassクラスの唯一のインスタンス。真の代表値。 Object#frozen? は
trueを返します。 false-
FalseClassクラスの唯一のインスタンス。
nilとfalseは偽を表します。 Object#frozen? はtrueを返します。 __FILE__-
現在のソースファイル名
フルパスとは限らないため、フルパスが必要な場合は
File.expand_path(__FILE__)とする必要があります。なお、現在のソースファイルのあるディレクトリの絶対パスは Kernel?.__dir__ メソッドで得られます。
__LINE__-
現在のソースファイル中の行番号
__ENCODING__-
現在のソースファイルのスクリプトエンコーディング
擬似変数の値を変更することはできません。擬似変数へ代入すると文法エラーになります。
定数
定数として使えるさまざまな識別子Foo # ASCII の範囲の大文字で始まる
Foo # 全角ラテン文字大文字で始まる
Ĉapelo # 非 ASCII のラテン文字大文字で始まる
Στιλό # ギリシャ文字大文字で始まる
Думи # キリル文字大文字で始まる
アルファベット大文字([A-Z])で始まる識別子は定数です。他にも、ソースエンコーディングが Unicode のときは Unicode の大文字またはタイトルケース文字(Lj〔U+01C8〕のように大文字+小文字の形の合字)から始まる識別子も定数です。
Unicode 以外のときは、そのエンコーディングが大文字と分類する文字(CP932 の全角ラテン大文字など)から始まる識別子が定数です。この分類は文字の種類(ctype)によるもので、String#downcase などの大文字小文字変換ができるかどうかとは独立です(例えば CP932 の A は
downcase では変換されませんが、A で始まる識別子は定数になります)。
定数の定義(と初期化)は代入によって行われますが、メソッドの中では定義できません。
一度定義された定数に再び代入を行おうとすると警告メッセージが出ます。
定義されていない定数にアクセスすると例外 NameError が発生します。
定数はその定数が定義されたクラス/モジュール定義の中(メソッド本体やネストしたクラス/モジュール定義中を含みます)、クラスを継承しているクラス、モジュールをインクルードしているクラスまたはモジュールから参照できます。クラス定義の外(トップレベル)で定義された定数は Object に所属することになります。
例class Foo
FOO = 'FOO' # クラス Foo の定数 FOO を定義(Foo::FOO)
end
class Bar < Foo
BAR = 'BAR' # クラス Bar の定数 BAR を定義(Bar::BAR)
# 親クラスの定数は直接参照できる
p FOO # => "FOO"
class Baz
# ネストしたクラスはクラスの継承関係上は無関係であるがネス
# トの外側の定数も直接参照できる
p BAR # => "BAR"
end
end
またクラス定義式はクラスオブジェクトの生成を行うと同時に、名前がクラス名である定数にクラスオブジェクトを代入する動作をします。クラス名を参照することは文法上は定数を参照していることになります。
class C
end
p C # => C
あるクラスまたはモジュールで定義された定数を外部から参照するためには :: 演算子を用います。また Object クラスで定義されている定数(トップレベルの定数と言う)を確実に参照するためには左辺無しの :: 演算子が使えます。
module M
I = 35
class C
end
end
p M::I # => 35
p M::C # => M::C
p ::M # => M
M::NewConst = 777 # => 777
定数参照の優先順位
定数参照時の定数の探索順序には、以下の3つの場合があります。
::で始まる定数参照::を含まない定数参照- 他の値から
::で繋げられた定数参照
:: で始まる定数参照
定数参照が :: で始まる場合、Object クラスを起点としてそのスーパークラスを順番に探索し、最初に見つかった定数を参照します。
X = 1
# 以下のように書いても同じ
# class Object
# X = 1
# end
module M
X = 2
p ::X # => 1
end
class BasicObject
X = 1
end
module M
X = 2
p ::X # => 1
end
:: を含まない定数参照
定数参照が :: を含まない場合、定数参照の場所を起点としてソースコードにおけるクラス(あるいはモジュール。以下同じ)のネストを外側に向かって探索し、最初に見つかった定数を参照します。一番外側のクラスまで探索しても定数が見つからなかった場合、起点のクラスのスーパークラスを順番に探索します。
X = "Object" # Object::X として定義される
class C
X = "C"
end
module M1
X = "M1"
module M2
class C3 < C
# C3 -> M2 -> M1 -> C -> Object の順で探索される
p X # => "M1"
end
end
end
なお以下の例では X の参照箇所からソースコード上でクラスのネストを外側にたどると M2 のみに遭遇するため、
M1 は探索されないことに注意してください。
X = "Object"
class C
X = "C"
end
module M1
X = "M1"
end
module M1::M2
class C3 < C
# C3 -> M2 -> C -> Object の順で探索される
p X # => "C"
end
end
ネストしているクラスの一覧は Class.nesting(あるいは Module.nesting)で取得できます。
module M1
module M2
p Module.nesting # => [M1::M2, M1]
end
end
module M1::M2
p Module.nesting # => [M1::M2]
end
他の値から :: で繋げられた定数参照
他の値から :: で繋げられた定数参照の場合、:: の前にあるクラスを起点としてそのスーパークラスを順番に探索し、最初に見つかった定数を参照します。ただし、Object クラスとそのスーパークラスは探索対象となりません。
X = "Object"
Y = "Object"
class C
X = "C"
end
class D < C
end
p D::X # => "C"
p D::Y # ~> NameError: uninitialized constant D::Y
:: を含まない定数参照と異なり、クラスのネストの外側は探索対象となりません。
module M
X = "M"
class C
end
p C::X # ~> NameError: uninitialized constant M::C::X
end