3

Ruby 在类和对象方面非常一致。但是,当涉及到顶级方法声明时,该规则会以某种方式失效。例如,

$ puts self # => main
$ puts self.class # => Object

但是,在此main对象的上下文中声明的方法以某种方式可用作 class 的私有方法Object

这有什么合乎逻辑的解释吗?我知道这非常方便,因为这些方法显示为“独立函数”,但是将其视为“它就是这样”会破坏其他一致的规则,因为通常您必须在类的上下文中定义一个方法使其成为该类的方法。但是,main对象不是 class Object,也根本不是 class 。

重新构建我的问题: 在 ruby​​ 的 REPL 中声明该方法的范围是什么?{类对象/对象主或模块内核}

关于 REPL 中声明的方法的私有性质,请参见以下示例:

def my_method # "a method declared in REPL"
  puts "method called"
end

# calling my_method in REPL aka top-level scope
my_method # => "method called"
[].my_method # => private method `my_method' called for []:Array (NoMethodError)
Array.my_method # => private method `my_method' called for Array:Class (NoMethodError)

Q:如果my_method被定义为Object类下的私有方法,那为什么self设置为main而不是Object类。如果有人说它不在私有范围内,那么为什么我会遇到上述错误?

4

3 回答 3

3

Although I'm not sure I fully understand the question, I'll try to answer:

When you're working inside irb you're really working in a context like this:

class Object
  # you're here
end

So, if you declare a method inside the REPL you're actually declaring it inside main's class:

ruby-1.9.3-rc1 :001 > def foo; end
 => nil 
ruby-1.9.3-rc1 :002 > self.class.public_methods.include?(:foo)
 => true 

I'm not sure where you get the idea that the methods defined there are private to the class (but again, I might be misunderstanding the question).

The class you're inside in irb includes the Kernel module so that's why you have access to its functions (which, since you're inside the class, appear as stand-alone functions even though they're regular methods):

ruby-1.9.3-rc1 :003 > self.class.included_modules
 => [Kernel] 

This would make it consistent with the typical Ruby behavior and indeed, main is just self inside the Object class.

If you call self you'll receive main because that's the way it's instructed to do it through inspect. We can remove the #to_s method from self and see the real value:

ruby-1.9.3-p0 :001 > self
 => main 
ruby-1.9.3-p0 :002 > class << self; remove_method :to_s; end
 => #<Class:#<Object:0x007fc08387af00>> 
ruby-1.9.3-p0 :003 > self
 => #<Object:0x007fc08387af00 @prompt={:PROMPT_I=>"ruby-1.9.3-p0 :%03n > ", :PROMPT_S=>"ruby-1.9.3-p0 :%03n%l> ", :PROMPT_C=>"ruby-1.9.3-p0 :%03n > ", :PROMPT_N=>"ruby-1.9.3-p0 :%03n?> ", :RETURN=>" => %s \n", :AUTO_INDENT=>true}> 

Edit: Before moving forward I think you should clarify which Ruby version are you using, see the sample below for 1.9.3:

ruby-1.9.3-p0 :001 > def my_method
ruby-1.9.3-p0 :002?>     puts "method called"
ruby-1.9.3-p0 :003?> end
 => nil 
ruby-1.9.3-p0 :004 > 
ruby-1.9.3-p0 :005 >   [].my_method
method called
 => nil 
ruby-1.9.3-p0 :006 > Array.my_method 
method called
于 2012-07-13T17:15:17.630 回答
2

IMO 顶级方法是在module的上下文Kernel中定义的,而不是Object在 class 中,因此它们最终会出现在Object实例和类方法中(因为ClassclassKernel也包括):

def a_method
  "inside a_method"
end

public :a_method

p Object.a_method
p Object.new.a_method
p self.a_method
p Kernel.a_method

这允许它们在任何情况下使用。

更新:它更简单,Module.superclass是一个Object,所以当我们在其中定义一些东西时,Object它最终也会作为Module实例方法。And Class.superclassis a Module,所以它最终也成为所有类的类方法。并且因为Kernel.class是一个ModuleKernel.a_method是一个类的实例方法Module。嗯,真的很简单吗?

于 2012-07-13T19:39:08.680 回答
0

如果您问为什么可以在顶层定义方法/函数,而您不在任何类中,那么答案是您也可以在对象中为其所属的类定义方法。让我们看一个例子。

class C
  def f
    def g
      'g'
    end
    'f'
  end
end

C.new.g # NoMethodError: undefined method `g' for #<C:0x0>
C.new.f # => 'f'
C.new.g # => 'g'

不建议这样做,但在这种情况下是一致的。

于 2012-07-13T20:31:54.397 回答