为什么模块内的 ruby​​ 类不能与常规类具有相同的作用域?

Dav*_*lar 2 ruby scope

我有一个内部有类的模块,但我发现如果不指定模块路径,内部类无法访问封闭模块中的任何方法。

另一种看待它的方法是 module_function 似乎没有带入类中。

例子:

module MyMod
  def meaning
    42
  end

  class Foo
    def initialize
      puts "New Foo"
      puts "I can call #{MyMod.meaning} from here"
      puts "But I can't get to #{meaning} from here"
    end
  end

  def go
    puts "I can get to #{meaning} from here"
    bar = Foo.new
  end

  module_function :go, :meaning
  go
end
Run Code Online (Sandbox Code Playgroud)

如果运行此命令,您会在“但是我不能...”行中收到错误:

undefined local variable or method `meaning'
Run Code Online (Sandbox Code Playgroud)

但是,如果删除整个文件周围的 MyMod 位,则访问外部方法就没有问题。

有没有一种简单的方法可以让这些访问而无需提供完整路径?

(我对不包含完整路径吹毛求疵的原因之一是因为我使用http://redshift.sourceforge.net/script/来创建我可以实例化的 ruby​​ 脚本 - 而且它们没有清晰而简单的名称,例如“MyMod”,我可以将其添加到路径中,实际上我必须传递范围,即使它只是类的封闭范围)

Jör*_*tag 6

我有一个模块,里面有一个类,

不,你不知道。您有一个模块定义,其中包含一个类定义,但这并不会使该类成为嵌套类。Ruby 没有嵌套类

Ruby 不是BetaScalaNewspeak,Ruby 中没有嵌套类。

将模块或类定义嵌套在另一个模块或类定义内不会两个类/模块之间创建嵌套关系。它仅使常量引用外部类/模块名称空间的类/模块部分。

换句话说,两者之间没有区别

module Foo
  class Bar
  end
end
Run Code Online (Sandbox Code Playgroud)

class Quux
end

module Foo
  Bar = Quux
end
Run Code Online (Sandbox Code Playgroud)

嵌套常量,而不嵌套常量引用的对象。

但我发现如果不指定模块路径,内部类就无法访问封闭模块中的任何方法。

正是因为没有“封闭模块”。有一个词法封闭的模块定义,但不会Foo类和模块之间创建任何形式的关系MyMod

另一种看待它的方法是 module_function 似乎没有带入类中。

老实说,我不明白你的意思,“带入类”的方法意味着什么,但这Module#module_function不是魔法。它的作用完全按照文档所述:它采用模块的实例方法,将其复制为模块的单例类的实例方法,并生成原始实例方法private

你可以在 Ruby/Spec 中阅读它的规范,它相当简单。此外,Rubinius源代码、用于启动 Rubinius 内核的基本版本完整版本都具有相当的可读性。

最后,Module#module_function确实没有做更多的事情

class Module
  def module_function(*meths)
    meths.each do |meth|
      define_singleton_method(meth, &instance_method(meth).bind(self))
      private meth
    end

    self
  end
end
Run Code Online (Sandbox Code Playgroud)

如果运行此命令,您会在“但是我不能...”行中收到错误:

undefined local variable or method `meaning'
Run Code Online (Sandbox Code Playgroud)

原因很简单:该类Foo及其任何超类都没有任何该名称的方法,因此您当然会遇到异常。

但是,如果删除整个文件周围的 MyMod 位,则访问外部方法就没有问题。

不存在“外法”。Ruby 没有类似 Beta 的嵌套类。这才是造成你误解的根本原因。您期望 Ruby 表现得像 Beta,但事实并非如此。Ruby 从任何语言中汲取灵感,最引人注目的是(按重要性的粗略顺序排列)Smalltalk、Lisp、Perl 和 Clu,但 Beta 并不在其中。

这在这里有一个完全不同的原因:

undefined local variable or method `meaning'
Run Code Online (Sandbox Code Playgroud)

在顶层定义的方法被隐式定义为 的私有实例方法Object。这是因为顶层的默认定义::Object是。由于Foo继承自Object,方法查找最终会找到meaning中定义的方法Object

有没有一种简单的方法可以让这些访问而无需提供完整路径?

遗产。例如,Module#append_features由 调用Module#include,使该模块成为包含类的超类,因此该模块的所有实例方法都成为方法查找祖先链的一部分。

旁白:如果没有嵌套,那会Module::nesting做什么呢?嗯,是的,这是一个不幸命名的方法。术语“嵌套类”或“嵌套模块”在 OO 中具有明确定义的含义,可以一直追溯到 Beta。但这种方法是一种完全不同的嵌套:

它指的是模块定义的词法嵌套,而不是模块本身的嵌套。

例如,这些模块定义都定义了完全相同的模块,但定义文本具有不同的嵌套:

def meaning
  42
end

class Foo
  def initialize
    meaning
  end
end
Run Code Online (Sandbox Code Playgroud)

同样,这纯粹是模块定义的词法嵌套。模块本身没有嵌套;在所有这些情况下,模块本身都是相同的。这种嵌套影响常量查找

常量首先在封闭的模块定义中按词法向外查找,然后在继承链中向上查找。

还有另一种情况可以嵌套:创建嵌套的词法作用域,而所有其他词法作用域(脚本、模块/类定义和方法定义)不嵌套。换句话说,块和只有块可以访问self其封闭词法范围的局部变量(和)。

  • 术语说明:在 OO 中,*hierarchy* 通常指的是 *inheritance* 层次结构(对于具有继承的语言)、*type* 层次结构 () (对于具有子类型的语言)或委托链(对于具有原型的语言)代表团)。这里有*词汇嵌套*。特别是,在 Ruby 中,*定义*的*词法嵌套*不会(必然)创建*对象*的嵌套。这与 Beta、Newspeak 或 Scala 不同,其中嵌套类成为封闭类实例的成员,就像方法和实例变量一样。 (2认同)