Ruby什么类在没有显式接收器时获取方法?

时间:2016-09-12 15:21:51

标签: ruby methods

这里的随机问题。我不确定是否有这个术语,但我想知道你何时定义一个没有显式接收器的方法,你怎么知道哪个类得到了这个方法?这是上下文中的self吗?

在类定义的上下文中,

self是被定义的类,使用隐式接收器定义的方法被绑定到类,我们一直看到它。

但是,如果我在实例方法中定义一个方法,那么'sub_method'也会被放在外层类中:

[12] pry(main)> class A
[12] pry(main)*   def my_method
[12] pry(main)*     puts self
[12] pry(main)*     def sub_method
[12] pry(main)*       puts self
[12] pry(main)*     end  
[12] pry(main)*   end  
[12] pry(main)* end  
=> :my_method
[13] pry(main)> a = A.new
=> #<A:0x007fa588181d40>
[14] pry(main)> a.my_method
#<A:0x007fa588181d40>
=> :sub_method
[15] pry(main)> a.sub_method
#<A:0x007fa588181d40>
=> nil
[16] pry(main)> A.instance_methods(false)
=> [:my_method, :sub_method]

同样在顶级范围,selfmain,它是Object类的一个实例,但是在那里定义的方法已添加到Object,而不是main [21] pry(main)> def a.my_singleton [21] pry(main)* puts self [21] pry(main)* end => :my_singleton [22] pry(main)> a.singleton_methods => [:my_singleton] [23] pry(main)> A.instance_methods(false) => [:my_method, :sub_method] [33] pry(main)> def why_object? [33] pry(main)* puts self [33] pry(main)* end => :why_object? [34] pry(main)> why_object? main => nil [35] pry(main)> Object.instance_methods(false) => [:pry, :__binding__, :my_method, :sub_method, :why_object?] 单例类,这是我所期待的基于我如何看待其他单例方法的工作:

|USER1|USER2|USER3|USER11|USER22|

这里发生了什么,是否有这样的规则,或者是否只有这几个案例需要了解?

2 个答案:

答案 0 :(得分:6)

我认为你将“接收者”混淆为“消息接收者”,这是人们通常所说的术语和“接收者”,如“定义任何方法的目的地上下文”。

语法允许在方法内调用def,但在样式方面是非正统的。 Ruby的方法是使用define_method,您可以更好地控制该方法的位置。将def视为定义方法的简单方法,但上下文有点滑。如果在类上下文中调用它,则定义实例方法。如果在实例方法中调用它,则定义另一个实例方法。

更好的方法是将该方法包装在一个模块中,稍后您可以includeextend组合一个模块。

main上定义顶级范围内的方法意味着您希望它们普遍可用。最好的方法是强制它们进入Object。这就是为什么在这种情况下定义方法会匆忙变得混乱的原因所以不建议用于除了琐碎的程序以外的任何东西。

答案 1 :(得分:4)

Ruby中有三个隐式上下文。

最着名的是self,当前对象和默认接收器。

第二个众所周知的是用于常量查找的范围。从广义上讲,不断查找是词法向外,然后是继承向上,但有很多细微差别。 Ruby维护者将此上下文称为 cref

您所询问的是the third context, sometimes called the default definee。通常,默认的definee是最近的词汇封闭模块。但是,您已经发现了一个例外:在顶层,默认的definee实际上是Object(另外,默认的可见性private)。 instance_eval同时更改selfinstance_eval消息的接收方)和默认定义(接收方的单例类< / em>的)。 class_eval更改了接收者。