红宝石方法查找中的“实际"步骤是什么? [英] What are the *actual* steps in ruby's method lookup?

查看:82
本文介绍了红宝石方法查找中的“实际"步骤是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了有关该主题的stackoverflow帖子,以及几篇文章,其中包括入门手册Ruby方法查找什么是方法查找路径Ruby .另外,我检查了 Ruby Metaprogramming 2 中的对象模型一章,在几个聊天室中询问了问题,并做了

I've read stackoverflow posts on this topic as well as several articles which include A Primer on Ruby Method Lookup, What is the method lookup path in Ruby. In addition, I checked out the object model chapter in Ruby Metaprogramming 2, asked in a few chat rooms, and made this reddit thread. Short of learning C, I've done what I can to figure this out.

如上面的资源所述,在方法查找期间(例如)在诸如

As described by the resources above, these 6 places are checked (in order) during method lookup on a receiving object like fido_instance:

  1. fido_instance的单个类
  2. IClass(来自扩展模块)
  3. IClass(来自前置模块)
  4. 课程
  5. IClass(来自包含的模块)
  6. 超类(如果在这里找不到方法,请重复步骤4-6)

很显然,该图是不完整的,并且所有这些单例类都可能不是在现实世界中创建的.尽管如此,这6个步骤仍然有很多不足之处,并且不能涵盖以下情况.如果在fido_instance的单例类之上没有扩展/前置的IClass,则没有解释是否在fido_instance的单例类上执行了第4步.我不必假设,因为整个方法查找都会短路.

Obviously, the diagram is incomplete, and all of these singleton classes might not have been created in the real world. Still, those 6 steps leave a lot to be desired, and don't cover the following scenario. If there were no extended/prepended IClass above the singleton class of fido_instance, then there's no explanation of whether step 4 is executed on the singleton class of fido_instance. I have to assume not since the whole method lookup would short circuit.

如果我猜出了一组可以解释ruby方法查找行为的步骤,则可能看起来像这样:

If I were to guess a set of steps that could explain ruby's method lookup behavior, it might look like:

  1. 检查fido_instance.class中的方法. (显然,ruby不会使用自己的#class方法进行方法查找,但传达了过程的逻辑)
  2. 检查fido_instance.class.superclass的方法.继续添加.superclass并检查方法,直到没有超类为止. (再次,ruby不会使用自己的#superclass方法)
  3. 找不到
  4. 方法.从步骤1开始,这次查找#method_missing.
  1. check fido_instance.class for the method. (obviously, ruby isn't going to use its own #class method to do the method lookup, but it conveys the logic of the process)
  2. check fido_instance.class.superclass for the method. Keep adding .superclass and checking for the method until no superclasses are left. (again, ruby isn't going to use its own #superclass method)
  3. method wasn't found. Start at step 1, looking for #method_missing this time.

我还记得阅读过的内容,如果接收对象是一个类,则有一个单独的方法查找过程,但是我不记得在哪里.

I also recall reading that there's a separate method lookup process if the receiving object is a class, but I can't recall where.

那么不涉及C的正确,详细的解释是什么?

So what's the correct, detailed explanation that doesn't involve knowing C?

推荐答案

我认为第二个引用中有一个...宝石...是答案的核心:单例类的祖先.应用于您的对象,它将是:

There's a ... gem ... in that second ref that I think gets to the core of the answer: ancestors of the singleton class. Applied to your object, it would be:

fido_instance.singleton_class.ancestors

这将始终为您提供Ruby使用的方法查找的顺序.当您以这种方式查看它时,这非常简单,这是您问题的底线答案. Ruby将以singleton_class开头,并在寻找该方法的祖先处逐步发展.使用您的图表:

This will always give you the order of method lookup that Ruby uses. It's pretty simple when you view it this way, and that's the bottom line answer to your question. Ruby will start at the singleton_class and work its way up the ancestors looking for that method. Using your diagram:

fido.singleton_class.ancestors
=> [Fetch, WagTail, DogClass, Object, Kernel, BasicObject]

(注1:Bark不属于此输出,因为您使用的是extend而不是include.稍后将对此进行详细介绍.)

(Note1: Bark is not part of this output because you used extend instead of include. More on this in a second.)

(注2:如果直到BasicObject都找不到它,它将在同一祖先链中调用method_missing.)

(Note2: If it doesn't find it all the way up to BasicObject, then it will call method_missing up the same ancestry chain.)

在类上调用方法时没有什么不同,因为在Ruby类中,它只是类Class的一个实例.因此,DogClass.method1将在DogClass.singleton_class上搜索method1,然后像以前一样在其祖先链上进行搜索.

It's no different when calling a method on a class, because in Ruby a class it just an instance of class Class. So DogClass.method1 will search for method1 on DogClass.singleton_class and then up its ancestry chain, just like before.

DogClass.singleton_class.ancestors
=> [Bark, Class, Module, Object, Kernel, BasicObject]

由于您将extend用于Bark,因此我们可以在这里找到它!因此,如果Bark定义了方法bark,则可以调用DogClass.bark,因为该方法是在DogClass的singleton_class祖先中定义的.

Since you used extend for Bark, this is where we find it! So if Bark defined a method bark, then you can call DogClass.bark because that method is defined in DogClass's singleton_class' ancestors.

要了解祖先树是什么(而不是每次都依赖于打印出来),您只需要知道如何通过子类化,extendincludeprepend等来修改祖先.

To understand what that ancestry tree will be (instead of relying on printing it out every time), you simply need to know how the ancestry is modified by subclassing, extend, include, prepend, etc.

  1. 子类化为子类提供了其超类的整个祖先链.
  2. include在类C中添加模块会将该模块添加到祖先链中,该祖先链在C之后并在其他所有元素之前.
  3. prepend在类C中添加模块会将该模块添加到祖先链之前,包括C和任何当前前置的模块.
  4. def x.method1method1添加到x.singleton_class.类似地,x.extend(M)会将M添加到x.singleton_class的祖先(但不添加到x.class).请注意,后者正是BarkDogClass.singleton_class发生的情况,但同样可以应用于任何对象.
  1. Subclassing gives the child class the entire ancestry chain of its superclass.
  2. includeing a module in a class C adds that module into the ancestry chain after C and before everything else.
  3. prepending a module in a class C adds that module into the ancestry chain before everything, including C and any currently prepended modules.
  4. def x.method1 adds method1 to x.singleton_class. Similarly x.extend(M) will add M to the ancestry of x.singleton_class (but not to x.class). Note that the latter is exactly what happened with Bark and DogClass.singleton_class, but can equally apply to any object.

在上面的列表中省略了extend,因为它不会修改对象的祖先链.它确实修改了对象singleton_class的祖先-如我们所见,Bark已包含在DogClass.singleton_class.ancestors中.

Leaving out extend from the above list because it does not modify the object's ancestry chain. It does modify the ancestry of that object's singleton_class -- as we saw, Bark was included in DogClass.singleton_class.ancestors.

切线:

上面有关类方法的一点是我了解单例类对Ruby的重要性的关键.您显然无法在DogClass.class上定义bark,因为DogClass.class == Class并且我们不希望在Class上定义bark!那么,如何允许DogClass成为Class的实例,从而允许它具有为DogClass定义的(类)方法bark,而不是不相关的类?使用单例类!这样,在类C中通过def self.x定义类方法"就类似于C.singleton_class.send(:define_method, :x) {...}.

The bit about class methods above is the key to me for understanding how important singleton classes are to Ruby. You obviously can't define bark on DogClass.class, because DogClass.class == Class and we don't want bark on Class! So how can we allow DogClass to be an instance of Class, allowing it to have a (class) method bark that is defined for DogClass but not unrelated classes? Using the singleton class! In this way, defining a "class method", like by def self.x inside class C, is sort of like C.singleton_class.send(:define_method, :x) {...}.

这篇关于红宝石方法查找中的“实际"步骤是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆