今回はRubyの定数のお話。
Rubyにも定数があります。がやはりいろいろと細かく他の言語とは違うところもあります。
今回はそこについて。
Rubyで定数を宣言するには先頭が大文字であること。あとは構成文字に英数字、_が使えます。
定数の参照はレキシカルに決定されます。
1 2 3 4 |
Max = 10 Min = 10 M1 = 1 M_ = 3 |
で、定数なんですがRubyでは再度代入ができます。警告はでるけど。
定数のクセに代入できるのかよ、と思うがRubyから入ったらそうは思うこともないのだろうか。
1 2 3 4 |
Max = 10 p Max #⇒10 Max = 20 # 警告が発生 p Max #⇒20 |
以下のようにするとスコープが異なるので警告は出ません
1 2 3 4 5 6 7 |
CONST = "TOP" class A CONST = "A" end p CONST p A::CONST |
クラス内での定義は
1 2 3 4 |
class Foo FOO = 'FOO' # クラス Foo の定数 FOO を定義(Foo::FOO) end p Foo::FOO |
継承した場合はこう。
1 2 3 4 5 6 7 |
class A1 CONST = "001" end class B1 < A1 p CONST #⇒"001" end |
これはわかるがではこうするとどうなるか
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class A NAME = "A" def name NAME end end class B < A NAME = "B" end puts B.new.name |
BをnewしているのでBで宣言しているNAMEがよばれるだろ。と思ってたら
結果は”A”になります。
これは定数がインスタンスではなくクラスに存在するためです。
なのでnameを呼び出したクラス内定数であるNAME=”A”が呼ばれます。
よってclass AのNAME定数がない場合は”`name’: uninitialized constant A::NAME (NameError)”が呼ばれます。Bは呼ばれません
定数でない場合、ローカル変数、インスタンス変数の場合は動きが異なります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class A1 CONST = "001" const = "001-1" @a = "001-2" end class B1 < A1 p CONST # puts const # 宣言されていないとしてエラーになる p @a # ⇒nil end B1.new |
さらにクラスの中にクラスの場合は
1 2 3 4 5 6 7 8 9 10 11 |
class C CONST = "C" class Ca CONST = "Ca" end class Cb < Ca p CONST end end |
どうなるか?
Rubyの定数は使われている定数の場所がネストされている場合は内側から順に定数の探索されます。
上の例だだとCbクラス内でCONSTの定数はない(レキシカルスコープに定数がない場合)はスーパークラスの探索を行います。
じゃあCaが呼ばれるのかというとCbから最も近いものとして”C”が呼ばれます。この辺りが良く混乱する。
Caのほうを呼びたいんだよ!という場合はCa::CONSTで明示的にすればOK。というかこうしておいたほうがわかりやすい。
ちなみに一応CクラスにあるCONST=”C”がない場合はスーパークラスであるCaのほうのCONSTが呼ばれます。
今回はRubyの定数のお話でした。