Rubyにおけるネストした定数
ネストした定数を定義する
たとえば
code:rb
module M
A = 1
class B
A = 2
end
class C
end
end
# 一見同じ定数 A にみえるけど M::A と M::B::A は異なる
M::A # => 1
M::B::A # => 2
上の例は次のように書き換えできる
code:rb
module M; end
M::A = 1
class M::B; end
M::B::A = 2
class M::C; end
# そりゃあそう
M::A # => 1
M::B::A # => 2
ネストした定数を参照する
すでに上に書いたけど、基本的にはモジュールやクラスを :: で繋いで参照する
M::A など
ネストしたスコープの中で指定した定数が見つからない場合
まずはネストの外側を探す
上のコード例の続きとして、
code:rb
module M
class C
A # => 1 (M::C::A は未定義なので M::A を探す。 M::A は定義済みなのでそれを参照する)
end
end
理解を深めるために、たとえばこれはどうなる?
code:rb
module M
class C
p A # => 1 (これは M::A を参照している)
A = 3
p A # => 3 (これは M::C::A を参照している)
end
end
M::C クラスの中で定数 A を定義したので M::C::A が定義されたことになる
定義後であれば M::C クラス内の A は M::C::A を参照することになる
見つからない場合は継承チェーンを辿って探す
code:rb
class Foo
A = 1
end
class Bar
class Baz < Foo
p A # => 1 (Bar::Baz::A を探す -> Bar::A を探す -> Foo::A を探す -> 発見!)
end
end
? 外側(Bar)にあった場合はどうなるか
ここまでの説明の通り、外側が優先になる(継承チェーンは辿らない)
code:rb
class Foo
A = 1
end
class Bar
A = 'hey!'
class Baz < Foo
p A # => "hey!" (Bar::Baz::A を探す -> Bar::A を探す -> 発見!)
end
end
? 外側の継承チェーンは辿るか
外側の継承チェーンは辿らない
継承チェーンを辿るのはあくまでself(定数を呼び出したスコープのモジュールやクラス)のみ
code:rb
class Foo
A = 1
end
class Bar < Foo
class Baz
p A # Bar::Baz::A を探す -> Bar::A を探す -> ない!!
# => uninitialized constant Bar::Baz::A (NameError)
end
end
これ間違えそう〜〜、つい、外側の継承チェーンも辿りたくなっちゃいそうだな