这是原始SO问题的延续:Using "::" instead of "module ..." for Ruby namespacing
在最初的SO问题中,这里是我仍然无法理解的情景:
FOO = 123
module Foo
FOO = 555
end
module Foo
class Bar
def baz
puts FOO
end
end
end
class Foo::Bar
def glorf
puts FOO
end
end
puts Foo::Bar.new.baz # -> 555
puts Foo::Bar.new.glorf # -> 123
有人可以提供一些解释为什么第一个电话返回555以及为什么第二个电话返回123?
答案 0 :(得分:34)
您可以将module Something
,class Something
或def something
的每个外观都视为新范围内的“网关”。当Ruby搜索已被引用的名称的定义时,它首先查找当前作用域(方法,类或模块),如果找不到它,则它将返回每个包含“gateway”并搜索那里的范围。
在您的示例中,方法baz
定义为
module Foo
class Bar
def baz
puts FOO
end
end
end
因此,在尝试确定FOO
的值时,首先检查类Bar
,并且由于Bar
不包含FOO
,搜索会向上移动“class Bar
网关”进入Foo
模块,该模块是包含范围。 Foo
确实包含常量FOO
(555),因此这是您看到的结果。
方法glorf
定义为:
class Foo::Bar
def glorf
puts FOO
end
end
此处“网关”为class Foo::Bar
,因此在FOO
内找不到Bar
时,“网关”会通过Foo
模块并直接进入顶部等级,其中有另一个显示的FOO
(123)。
请注意如何使用class Foo::Bar
创建单个“网关”,跳过Foo
的范围,但module Foo; class Bar ...
会打开两个单独的“网关”
答案 1 :(得分:6)
检查出来:
FOO = 123
module Foo
FOO = 555
end
module Foo
class Bar
def baz
puts FOO
end
def glorf3
puts ::FOO
end
end
end
class Foo::Bar
def glorf2
puts Foo::FOO
end
def glorf
puts FOO
end
end
puts Foo::Bar.new.baz # -> 555
puts Foo::Bar.new.glorf # -> 123
puts Foo::Bar.new.glorf2 # -> 555
puts Foo::Bar.new.glorf3 # -> 123
所以我的想法是,当你定义:
module Foo
FOO = 555
end
您正在FOO
的命名空间中创建Foo
。所以当你在这里使用它时:
module Foo
class Bar
def baz
puts FOO
end
end
end
您位于Foo
名称空间中。但是,当你在:
class Foo::Bar
def glorf
puts FOO
end
end
FOO
来自默认命名空间(如::FOO
所示)。
答案 2 :(得分:0)
第一个电话:
puts Foo::Bar.new.baz # -> 555
打印调用类 Foo :: Bar
的实例的方法 baz 的结果请注意 Foo :: Bar#baz 定义实际上是FOO上的关闭。遵循ruby的范围规则:
第二个电话:
puts Foo::Bar.new.glorf # -> 123
打印调用类 Foo :: Bar
的实例的方法 glorf 的结果注意 Foo :: Bar #glorf 这次定义也是FOO的关闭,但是如果我们遵循ruby的范围规则你会注意到值已关闭在这个时间是 :: FOO (顶级范围FOO),方式如下:
答案 3 :(得分:0)
glorf是=> [Foo, Module, Object, Kernel, BasicObject]
在该范围内(即在默认/主模块中),FOO被指定为123
模块Foo定义为
module Foo
FOO = 555
class Bar
def baz
puts FOO
end
end
end
其中方法baz属于模块Foo => [Bar, Foo, Object, Kernel, BasicObject]
并且在该范围内FOO被指定为555