Ruby对类和对象非常一致。但是,当涉及到顶级方法声明时,该规则会以某种方式发生故障。例如,
$ puts self # => main
$ puts self.class # => Object
但是,在此main
对象的上下文中声明的方法在某种程度上可用作类Object
的私有方法。
这有什么合理的解释吗?我知道这非常方便,因为这些方法看起来像“独立函数”,但是把它当作“它就是这样”会打破其他方面一致的规则,因为通常你必须在类的上下文中定义一个方法因为它是该类的一种方法。但是,main
对象不是类Object
,也不是类。
重新构思我的问题: 在ruby的REPL中声明方法的范围是什么? {class Object / object main或module Kernel}
关于在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)
问:如果my_method被定义为Object类下的私有方法,那么为什么self被设置为main而不是class Object。如果有人说它不在私人范围内,那为什么我会得到上述错误?
答案 0 :(得分:3)
虽然我不确定我是否完全理解这个问题,但我会尽力回答:
当你在irb
内工作时,你真的在这样的环境中工作:
class Object
# you're here
end
所以,如果你在REPL中声明一个方法,你实际上是在main
的类中声明它:
ruby-1.9.3-rc1 :001 > def foo; end
=> nil
ruby-1.9.3-rc1 :002 > self.class.public_methods.include?(:foo)
=> true
我不确定你在哪里知道那里定义的方法是私有的(但同样,我可能会误解这个问题)。
您在irb
内的课程包含Kernel
模块,这就是您可以访问其功能的原因(因为您在课堂内,它们甚至可以显示为独立功能)虽然他们是常规方法):
ruby-1.9.3-rc1 :003 > self.class.included_modules
=> [Kernel]
这会使它与典型的Ruby行为一致,实际上,main
只是Object类中的self
。
如果您致电self
,您将收到main
,因为这是通过检查指示的方式。我们可以从#to_s
中移除self
方法并查看实际值:
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}>
编辑:在继续前进之前,我认为您应该澄清您使用的是哪个Ruby版本,请参阅下面的示例以获取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
答案 1 :(得分:2)
IMO顶级方法在Kernel
模块的上下文中定义,而不是Object
类,因此它们最终都在Object
实例和类方法中(因为Class
类也包含Kernel
):
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
结尾实例方法也是如此。 Class.superclass
是Module
,所以它最终也是所有类的类方法。由于Kernel.class
是Module
,Kernel.a_method
是类Module
的实例方法。嗯,真的很简单?
答案 2 :(得分: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'
不建议这样做,但在这种情况下它是一致的。