Ruby类的实例方法def initialize:是实例方法还是类方法?

6

让我们来看一个普通的 Ruby 类:

class Person
  attr_accessor :name
  def initialize name
    @name = name
  end
end

bob = Person.new("bob")

我的问题是关于初始化的本质。事实上,new显然是一个类方法,但我认为initialize是一个实例方法(不是类方法),它在调用类方法new创建实例时被调用。
我的理解正确吗?或者有人能够提供新的见解吗?我已经做了一些谷歌搜索,但没有找到任何明确的答案。

1
它有点独特 - 您可以从中访问实例方法作用域,但正如您所说,它可像类方法一样调用。请注意,如果定义了 def self.new,则不会调用初始化。 - max pleaner
这是否意味着它是由调用new方法而被称为结果?还是它本身就是new方法? - Andrew Kim
是的。请注意,Module#attr_accessor也是一个类方法,它创建了两个实例方法(这里是namename=)。 - Cary Swoveland
2
@maxpleaner:这并不是什么独特的东西。实际上,你可以用三行非常简单的 Ruby 代码表达 new 的语义:obj = allocate; obj.send(:initialize, *args, &block); return obj 这里唯一“独特”的方法是 allocate,它的语义无法在 Ruby 中表达:它从对象内存中分配一个空对象,并将其类指针设置为 self - 这两个事情都无法从 Ruby 中解释。但即便如此,它仍然是一个普通的方法,可以像任何其他方法一样被覆盖和重写...只是不能用 Ruby 编写。 - Jörg W Mittag
1个回答

7
当初始化一个新对象时(也就是在类上调用new方法),实际上会调用这个方法:
class Class
  def new(*args, &block)
    obj = allocate
    obj.send(:initialize, *args, &block)
    obj
  end
end

在标准的Ruby实现中,这个方法是用C实现的,但是有很好的文档
要理解这里发生了什么,你必须知道在Ruby中,即使类也是对象(它们是Class类的实例)。因此,当在你的Person类上调用new时,你实际上是在Class对象的实例上调用new方法。
正如你所看到的,Person类(作为Class本身的一个实例)带来了一种为新实例分配内存的方法,名为bob。在分配内存后,new方法调用initialize以初始化新创建的实例。

实际上,“initialize”默认是“private”的,所以中间那行代码其实更像是“obj.send(:initialize, *args, &block)” ,但最终的结果是一样的。如果你曾经使用过Objective-C,你应该会发现它很熟悉,因为“Foo.alloc.init”基本上就是创建对象的方式。 - Jörg W Mittag
感谢@JörgWMittag。我修正了代码,并学到了更多关于C-Ruby中方法调度的工作原理。 - Holger Just

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接