关于全局/范围的Ruby方法查找

关于全局/范围的Ruby方法查找,ruby,methods,Ruby,Methods,我试图全面理解Ruby是如何定位方法/符号的,但当它涉及多个级别时,尤其是全局/文件范围时,我很难理解 当在类上显式调用方法时,有很多关于类及其包含的模块的搜索顺序的说明(因此在每种情况下,super调用什么)。但是当不显式调用方法时,例如普通的func-args而不是self.func-args时,搜索顺序是什么 为什么在我下面的示例中,调用func的成员方法在全局方法之前找到成员方法,而func2在没有调用method\u的情况下找到全局方法? 当全局变量改为模块/类/类型时,为什么找不到具

我试图全面理解Ruby是如何定位方法/符号的,但当它涉及多个级别时,尤其是全局/文件范围时,我很难理解

当在类上显式调用方法时,有很多关于类及其包含的模块的搜索顺序的说明(因此在每种情况下,
super
调用什么)。但是当不显式调用方法时,例如普通的
func-args
而不是
self.func-args
时,搜索顺序是什么

为什么在我下面的示例中,调用
func
的成员方法在全局方法之前找到成员方法,而
func2
在没有调用
method\u的情况下找到全局方法?
当全局变量改为模块/类/类型时,为什么找不到具有相同名称的成员

当语言在方法中遇到“
func
func()
func arg
”等时,是否有任何官方文档说明它的具体操作?有很多第三方博客,但他们只讨论了带有
include Module
class-Type
的单个实例

def func; "global func" end
def func2; "global func 2" end

class Test
  def x; func end
  def y; func2 end
  def z; Math end
  def w
    func = "local_var"
    [func(), func]
  end


  def func(arg=nil); "method func" end
  def func=(x); puts "assign func=" end
  def Math; "method Math" end

  def method_missing(sym, *args, &block)
    puts "method_missing #{sym}"
    super(sym, *args, &block)
  end
end

x = Test.new
puts x.x.inspect # "method func", member overrides global
puts x.y.inspect # "global func 2", "method_missing" was not called
puts x.z.inspect # "Math" module, member did not override global
puts x.w.inspect # ["method_func", "local_var"], local variables are always considered before anything else

Ruby的方法查找算法实际上非常简单:

  • 检索接收器的
    指针
  • 如果该方法存在,则调用它
  • 否则检索
    超类
    指针,然后重复
就这样

如果算法到了不再有超类的地步,但仍然没有找到方法,它将重新启动整个过程,并将
method\u missing
作为消息,原始消息的名称放在参数前面。但就是这样。这就是整个算法。它非常小且非常简单,而且必须非常小且非常简单,因为方法查找是面向对象语言中最常执行的操作

注意:我完全忽略了/因为我对它的工作原理了解不够。我只知道它的作用,这对我来说已经足够了

还要注意:我忽略了性能优化,比如在多态内联缓存中缓存方法查找的结果

好的,但这里有个窍门:那些
类和
超类的指针到底指向哪里?好吧,它们并不指向和方法返回的内容。所以,让我们退一步

每个对象都有一个指向对象类的
class
指针。每个类都有一个指向其超类的
指针

让我们开始一个运行示例:

class Foo; end
现在,我们有了类
Foo
,它的
超类
指针指向
对象

foo = Foo.new
我们的对象
foo
class
指针指向
foo

def foo.bar; end
现在事情开始变得有趣起来。我们创建了一个单例方法。实际上,没有单例方法,它只是单例类中的一个普通方法。那么,这是如何工作的呢?现在,
class
指针指向
foo
的单例类和
foo
的单例类的
超类
指针指向
foo
!换句话说,singleton类被插入到
foo
和它的“real”类
foo
之间

def foo.bar; end
但是,当我们询问
foo
其类时,它仍然会回答
foo

foo.class #=> Foo
Object#class
方法知道单例类,并简单地跳过它们,跟随
superclass
指针,直到找到一个“普通”类,并返回该类

下一个并发症:

module Bar; end

class Foo
  include Bar
end
这里发生了什么?Ruby创建了一个名为include类的新类(我们称之为
Barʹ
)。此类的方法表指针、类变量表指针和常量表指针指向
Bar
的方法表、类变量表和常量表。然后,Ruby使
Barʹ
超类
指针指向
Foo
的当前超类,然后使
Foo
的超类指针指向
Barʹ
。换句话说,包含模块将创建一个新类,该类将作为包含模块的类的超类插入

这里有一点复杂:您还可以
模块包含到模块中。这是怎么回事?好的,Ruby只是跟踪包含在模块中的模块。然后,当模块被包含到一个类中时,它将对每个包含的模块递归地重复上述步骤

关于Ruby方法查找,您只需要了解这些:

  • 找班
  • 跟随超类
  • 单例类插入对象上方
  • 包含类插入上述类
现在让我们看看你的一些问题:

当在类上显式调用方法时,有很多关于类及其包含的模块的搜索顺序的说明(因此在每种情况下,
super
调用什么)。但是当不显式调用方法时,例如普通的
func-args
而不是
self.func-args
时,搜索顺序是什么

同样的
self
是隐式接收器,如果未指定接收器,则接收器为
self
。和括号是可选的。换言之:

func args
完全一样

为什么在我下面的示例中,调用
func
的成员方法在全局方法之前找到成员方法,而
func2
在没有调用
method\u的情况下找到全局方法

Ruby中没有“全局方法”这样的东西。也没有所谓的“成员方法”。每个方法都是一个实例方法。时期没有全局、静态、类,
Math
self.Math
Math()
self.func = 'setter method'