首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ruby - Lexical作用域与继承

Ruby - Lexical作用域与继承
EN

Stack Overflow用户
提问于 2013-02-28 02:39:37
回答 4查看 3.2K关注 0票数 34

这是这个原始问题的延续:Using "::" instead of "module ..." for Ruby namespacing

在最初的SO问题中,这里是我仍然无法理解的场景:

代码语言:javascript
复制
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吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-03-04 01:02:01

您可以将module Somethingclass Somethingdef something的每次出现视为进入新作用域的“网关”。当Ruby搜索已被引用的名称的定义时,它首先在当前作用域(方法、类或模块)中查找,如果在当前作用域中找不到,它将返回包含“gateway”的每个作用域,并在那里搜索作用域。

在您的示例中,方法baz被定义为

代码语言:javascript
复制
module Foo
  class Bar
    def baz
      puts FOO
    end
  end
end

因此,当尝试确定FOO的值时,首先检查类Bar,由于Bar不包含网关,因此搜索将通过“class Bar FOO”向上移动到包含范围的Foo模块。Foo确实包含一个常量FOO (555),因此这是您看到的结果。

方法glorf的定义如下:

代码语言:javascript
复制
class Foo::Bar
  def glorf
    puts FOO
  end
end

这里的“网关”是class Foo::Bar,所以当在Bar中找不到FOO时,“网关”通过Foo模块,直接进入顶层,在那里有另一个FOO (123),这就是所显示的内容。

注意使用class Foo::Bar如何创建一个“网关”,跳过Foo的作用域,但module Foo; class Bar ...打开两个独立的“网关”

票数 36
EN

Stack Overflow用户

发布于 2013-02-28 03:14:45

哇,问得好。我能想到的最好的答案是,在这种情况下,您使用模块来定义名称空间。

看看这个:

代码语言:javascript
复制
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

所以我的想法是,当你定义:

代码语言:javascript
复制
module Foo
  FOO = 555
end

您正在Foo的名称空间中创建FOO。所以当你在这里使用它的时候:

代码语言:javascript
复制
module Foo
  class Bar
    def baz
      puts FOO
    end
  end
end

您位于Foo命名空间中。但是,当您在中引用它时:

代码语言:javascript
复制
class Foo::Bar
  def glorf
    puts FOO
  end
end

FOO来自默认名称空间(如::FOO所示)。

票数 6
EN

Stack Overflow用户

发布于 2013-03-02 06:16:52

第一个调用:

代码语言:javascript
复制
puts Foo::Bar.new.baz    # -> 555

打印调用类Foo::Bar的实例的方法baz的结果

请注意,Foo::Bar#baz definition 实际上是FOO上的闭包。下面是ruby的作用域规则:

  1. FOO Foo::
  2. FOO (类,而不是实例)作用域中搜索
  3. FOO,找不到它,在封闭作用域Foo (因为我们在模块定义中)中搜索它,并在(555)

中找到它

第二个调用:

代码语言:javascript
复制
puts Foo::Bar.new.glorf  # -> 123

打印调用类Foo::Bar的实例的方法glorf的结果

注意,这次Foo::Bar#glorf定义也是FOO上的一个闭包,但是如果我们遵循ruby的作用域规则,你会注意到这个时候关闭的值是::FOO (顶级作用域FOO),如下所示:

  1. FOO是在found
  2. FOO Foo::(类,而不是实例)名称空间中搜索的,它不是在封闭的作用域(‘顶层’)中搜索的,而是在(123)

中找到的

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15119724

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档