Ruby类方法与特征类中的方法

类的本征类(或元类)中的类方法和方法只有两种方法来定义一个东西吗?

否则,有什么区别?

class X # class method def self.a "a" end # eigenclass method class << self def b "b" end end end 

XaXb表现有何不同?

我认识到我可以通过打开本征类来覆盖或别名类方法:

 irb(main):031:0> class X; def self.a; "a"; end; end => nil irb(main):032:0> class X; class < # irb(main):033:0> Xa => "a" irb(main):034:0> Xb => "a" irb(main):035:0> class X; class < nil irb(main):036:0> Xa => "c" 

这两种方法是等价的。 ‘eigenclass’版本有助于使用attr_ *方法,例如:

 class Foo @instances = [] class << self; attr_reader :instances end def initialize self.class.instances << self end end 2.times{ Foo.new } p Foo.instances #=> [#, #] 

您还可以使用define_singleton_method在类上创建方法:

 Foo.define_singleton_method :bim do "bam!" end 

在Ruby中,确实没有类方法这样的东西。 由于一切都是Ruby中的对象(包括类),当你说def self.class_method ,你只是在类Class的实例上定义一个单例方法。 所以回答你的问题,说

 class X def self.a puts "Hi" end class << self def b puts "there" end end end Xa # => Hi Xb # => there 

有两种方式说同样的话。 这两种方法都只是在您的Class对象实例中定义的singeton(eigen,meta,ghost或任何你想称之为的方法)方法,在你的例子中是X 这个主题是元编程的一部分,这是一个有趣的话题,如果你已经使用Ruby一段时间了,你应该看看。 实用程序员有一本关于元编程的好书 ,如果你对这个主题感兴趣,你一定要看看。

还有另一个死灵法师来揭示这个老问题……你可能没有意识到的一件事是将一个类方法标记为private (使用private关键字而不是:private_class_method )与标记一个本征类方法不同。 :

 class Foo class << self def baz puts "Eigenclass public method." end private def qux puts "Private method on eigenclass." end end private def self.bar puts "Private class method." end end Foo.bar #=> Private class method. Foo.baz #=> Eigenclass public method. Foo.qux #=> NoMethodError: private method `qux' called for Foo:Class # from (irb) 

以下示例将与前一个示例有关:

 class Foo class << self def baz puts "Eigen class public method." end private def qux puts "Private method on eigenclass." end end def bar puts "Private class method." end private_class_method :bar end Foo.bar #=> NoMethodError: private method `bar' called for Foo:Class # from (irb) Foo.baz #=> Eigen class public method. Foo.qux #=> NoMethodError: private method `qux' called for Foo:Class # from (irb) 

Ruby中使用的大多数实例方法都是全局方法。 这意味着它们可以在定义它们的类的所有实例中使用。 相反,单个方法是在单个对象上实现的。

有一个明显的矛盾。 Ruby在类中存储方法,所有方法都必须与类相关联。 定义单例方法的对象不是类(它是类的实例)。 如果只有类可以存储方法,那么对象如何存储单例方法? 创建单例方法时,Ruby会自动创建一个匿名类来存储该方法。 这些匿名类称为元类,也称为单例类或特征类。 单例方法与元类相关联,而元类又与定义单例方法的对象相关联。

如果在单个对象中定义了多个单例方法,则它们都存储在同一个元类中。

 class Zen end z1 = Zen.new z2 = Zen.new def z1.say_hello # Notice that the method name is prefixed with the object name puts "Hello!" end z1.say_hello # Output: Hello! z2.say_hello # Output: NoMethodError: undefined method `say_hello'… 

在上面的示例中,say_hello方法是在Zen类的z1实例中定义的,而不是在z2实例中定义的。

以下示例显示了定义单例方法的不同方法,结果相同。

 class Zen end z1 = Zen.new z2 = Zen.new class << z1 def say_hello puts "Hello!" end end z1.say_hello # Output: Hello! z2.say_hello # Output: NoMethodError: undefined method `say_hello'… 

在上面的例子中,类<< z1将当前self改为指向z1对象的元类; 然后,它定义了元类中的say_hello方法。

上述两个例子都用于说明单例方法的工作原理。 但是,有一种更简单的方法来定义单例方法:使用名为define_singleton_method的内置方法。

 class Zen end z1 = Zen.new z2 = Zen.new z1.define_singleton_method(:say_hello) { puts "Hello!" } z1.say_hello # Output: Hello! z2.say_hello # Output: NoMethodError: undefined method `say_hello'… 

我们之前了解到类也是对象(内置类的实例,称为Class)。 我们还学习了类方法。 类方法只不过是与类对象关联的单例方法。

还有一个例子:

 class Zabuton class << self def stuff puts "Stuffing zabuton…" end end end 

所有对象都可能有元类。 这意味着类也可以有元类。 在上面的例子中,类<< self修改self,因此它指向Zabuton类的元类。 如果定义的方法没有显式接收器(将在其上定义方法的类/对象),则在当前作用域内隐式定义它,即self的当前值。 因此,stuff方法是在Zabuton类的元类中定义的。 上面的示例只是定义类方法的另一种方法。

阅读这篇关于Ruby Classes的文章 。