Ruby - 词法范围与继承

时间:2013-02-27 18:39:37

标签: ruby inheritance lexical-scope

这是原始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?

4 个答案:

答案 0 :(得分:34)

您可以将module Somethingclass Somethingdef 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的范围规则:

    Foo :: Bar (类,而不是实例)范围内搜索
  1. FOO ,找不到它,
  2. 在封闭范围 Foo 中搜索
  3. FOO (因为我们在模块定义范围内)并在那里找到(555)
  4. 第二个电话:

    puts Foo::Bar.new.glorf  # -> 123
    

    打印调用类 Foo :: Bar

    的实例的方法 glorf 的结果

    注意 Foo :: Bar #glorf 这次定义也是FOO的关闭,但是如果我们遵循ruby的范围规则你会注意到值已关闭在这个时间是 :: FOO (顶级范围FOO),方式如下:

    1. FOO Foo :: Bar (类,而非实例)命名空间中搜索,找不到
    2. FOO 在封闭范围内搜索(“顶级”)并在那里找到(123)

答案 3 :(得分:0)

glorf是=> [Foo, Module, Object, Kernel, BasicObject]

中Foo类的一种方法

在该范围内(即在默认/主模块中),FOO被指定为123

模块Foo定义为

module Foo
  FOO = 555
  class Bar
    def baz
      puts FOO
    end
  end
end

其中方法baz属于模块Foo => [Bar, Foo, Object, Kernel, BasicObject]

中的类Bar

并且在该范围内FOO被指定为555