Ruby的Class
类列出了两个名为' new'的方法:
Class::new
是公共类方法Class#new
是一个公共实例方法但是当我这样做时:
Class.methods(false)
#=> []
应该列出单例方法(我假设是什么类方法),我得到一个空数组。为什么会这样? Class::new
定义在哪里?
答案 0 :(得分:3)
文档中显示为::new
的方法通常为#initialize
,例如Range::new
:
new(begin,end,exclude_end = false)→rng
使用给定的
begin
和end
构造范围。如果省略exclude_end
参数或false
,则rng
将包含结束对象;否则,它将被排除在外。
这是因为您通过以下方式创建实例:
r = Range.new(0, 2) #=> 0..2
而不是:
r = Range.allocate #=> nil..nil
r.send(:initialize, 0, 2) #=> nil
r #=> 0..2
这正是::new
的作用 - 它通过allocate
创建一个新实例,发送它initialize
(传递参数)并返回实例。
实际new
方法继承自Class
(因为Range
是Class
的实例) - Class#new
:
new(args,...)→obj
调用
构造对象时最终调用的方法allocate
创建类类的新对象,然后调用该对象的initialize
方法,并将其传递给 args 。这是在使用.new。
就像allocate
,inherited
和superclass
(以及来自Class
'祖先的实例方法,例如Module
):
Range.method(:new)
#=> #<Method: Class#new>
Range.method(:allocate)
#=> #<Method: Class#allocate>
Range.method(:ancestors)
#=> #<Method: Class(Module)#ancestors>
所以,如果你致电Class.new
:
my_string_class = Class.new(String)
#=> #<Class:0x007fdf5485b200>
你只需调用Class#new
,它(再次)相当于:
my_string_class = Class.allocate
my_string_class.send(:initialize, String)
my_string_class
#=> #<Class:0x007fdf5484beb8>
一个值得注意的例外是Struct
,它实际上提供了自己的new
类方法:
Struct.method(:new)
#=> #<Method: Struct.new>
与其他类不同,Struct::new
不返回Struct
的实例,而是返回Class
的实例(Struct
的子类)。
答案 1 :(得分:2)
tl; dr summary :
为什么会这样?
因为它不是单身方法。
Class::new
定义在哪里?
不是。 调用 Class.new
只是调用Class#new
(因为Class
是其自身的实例)。 Foo::new
的文档实际上是任何类Foo#initialize
的{{1}}文档,包括Foo
本身。< / p>
如果你想了解一些关于Ruby的事情,那么自己问问她是个好主意:
Class
Object#method
方法返回表示方法的Method
对象。 (方法不是Ruby本身的对象,但是你可以得到一个代表方法的反射代理对象。)
您可以使用Method#owner
方法询问new_method = Class.method(:new)
#=> #<Method: Class#new (defined in Class at core/alpha.rb:90)>
定义的位置:
Method
如您所见,new
在Class
中定义,而不在new_method.owner
#=> Class
的单身类中定义。
您还可以使用Method#source_location
方法向Class
询问有关其Ruby源代码的位置:
Method
这告诉我们new_method.source_location
#=> ['core/alpha.rb', 90]
是在文件core/alpha.rb
on line 90中定义的:
Class#new
出于性能原因,该方法部分以字节码实现,但基本上只是:
def new(*args)
obj = allocate()
Rubinius.asm(args, obj) do |args, obj|
run obj
run args
push_block
send_with_splat :initialize, 0, true
# no pop here, as .asm blocks imply a pop as they're not
# allowed to leak a stack value
end
obj
end
现在,您可能会问自己:为什么在RDoc文档中有Class::new
的条目,如果该方法不存在?好吧,RDoc知道class Class
def new(*args, &block)
obj = allocate
obj.__send__(:initialize, *args, &block) # because initialize is private
#obj.initialize(*args, &block)
obj
end
end
之间的关系,这是您定义的方法,但通常不会直接调用,#initialize
这是您调用的方法,但通常不会...如果存在,它会将Class#new
记录为#initialize
。
所以,我们真正想看的是::new
:
Class#initialize
initialize_method = Class.method(:initialize)
#=> #<Method: Class#initialize (defined in Class at core/class.rb:15)>
initialize_method.owner
#=> Class
initialize_method.source_location
#=> ['core/class.rb', 15]
def initialize(sclass=Object, name=nil, under=nil)
raise TypeError, "already initialized class" if @instance_type
raise TypeError, "can't make subclass of Class" if Class.equal?(sclass)
set_superclass sclass
# Things (rails) depend on the fact that a normal class is in the constant
# table and have a name BEFORE inherited is run.
under.const_set name, self if under
if sclass
Rubinius.privately do
sclass.inherited self
end
end
super()
end
private :initialize
基本上做了三件事:
Class#inherited
钩子方法如果你想知道一开始就神奇地存在的一些核心类之间的关系,你可以看看一些Ruby执行引擎的初始化代码,例如:
VM::bootstrap_class
in machine/ontology.cpp
org.jruby.Ruby.initRoot
in core/src/main/java/org/jruby/Ruby.java
Src/ClassInitGenerator
mrb_init_class
in src/class.c
注意:根据您使用的Ruby实现,显然这些方法的定义位置以及定义方式可能会有所不同。
答案 2 :(得分:1)
new
被定义为Class
类的实例方法,而不是单例方法:
Class.instance_method :new # => #<UnboundMethod: Class#new>
需要注意的是:Class
(对象)本身也是Class
(类)的实例。
Class.instance_of? Class # => true