Ruby中的'self.method_name'和'class << self'有什么区别?

6

我曾试图将一个类的实例化限制为一个(不使用singleton),但未能成功。我尝试过使用类变量(@@),但没有成功。之后我在谷歌上搜索,找到了以下内容:

class A 
  @count = 0 

  class << self 
    attr_accessor :count 
  end

  def initialize val 
    @a = val 
    self.class.count += 1 
  end 
end 

a=A.new 42 
b=A.new 43

我搜索了关于'class << self'的解释,希望能找到更好的(或者更简单明了的),但是很遗憾没有找到。

最终,在进行了一些测试之后,我得出结论:'class << self'只是一个块包装器,你可以在其中定义类方法

所以,这是正确的吗?

谢谢!


你的第一句话并不是很有意义,因为如果你的类只能有一个实例,那么它就是单例,无论你如何实现这种行为。或者你是指单例类(特殊的类)吗? - John Topley
@John,我认为他指的是标准库中包含的“Singleton”类。 - horseyguy
4个回答

38
class << self符号打开了一个对象的特殊类,该特殊类称为元类,用于存储与实例相关的行为。在类的情况下,元类有时被称为元类(metaclass)。Ruby使用元类来实现所谓的“类方法”(也称为静态方法)。
正如Moritz所述,Ruby中的类也是一个对象,并且就其是对象而言,它也有一个类。在Ruby中,类的类称为Class
任何语言中的“类方法”都是接收器为类的方法,也就是说该方法是直接在类本身上调用的方法。但是,为了使方法能够在接收器上调用,必须在接收器的类上定义该方法。对于类,可以将“类方法”实现为Class类的实例方法。
但是,在Class上定义实例方法意味着所有类都可以访问该类方法,这并不理想。
于是乎,元类诞生了。正如前面所述,对象的元类是一个特殊的类,用于存储该对象唯一的方法。在类的情况下,元类是Class类的子类,并且是该类的直接类。
因此,Ruby中的“类方法”只是定义在类的元类上的“实例方法”。
"

def MyClass.my_method表示实际上是在MyClass的特殊类(eigenclass)中定义了my_method。如果你使用这种方法,你可以在一段时间内绕过理解特殊类的要求,因为你可以欺骗自己认为这只是Ruby定义“静态方法”的方式,并继续认为Ruby的类模型与Java相似。然而,class << self表示法不允许这种解释,你必须面对特殊类的现实。

总之,“类方法”实际上是在特殊类中定义的“实例方法”,而class << self使你可以访问特殊类。

更多阅读请查看以下链接:

"

http://banisterfiend.wordpress.com/2008/11/25/a-complete-ruby-class-diagram/

http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/

http://www.klankboomklang.com/2007/09/21/the-singleton-class/


很好的解释——我正在谷歌类<<self>>语法,现在我理解了整个类结构。谢谢! - csjacobs24
1
这里有一个相关问题:当您在特殊类中(即在class << self块内部)定义一个带有self.method_name的方法时,会发生什么?该方法最终会在哪个对象上?我不是在问它是否是个好主意,甚至建议……只是好奇它最终会出现在哪个对象上。 - GuyPaddock
2
我想知道@GuyPaddock的问题的答案。在class << self内部使用class << self确实将您置于eigenclass_of_the_eigenclass中,展示了Ruby的内部一致性。由于eigenclass是instance_of?(Class),因此它具有可用的singleton_class方法。因此,我们可以在singleton类上定义singleton类,然后在singleton类上定义singleton类,以此类推... - Tomboyo
你可以使用 eigenclass = class Dog; class << self; self; end; endeigen_eigenclass = class Dog; class << self; class << self; self; end; end; end 进行测试。请注意,eigenclass != eigen_eigencalss #=> trueeigenclass.singleton_class == eigen_eigenclass #=> true - Tomboyo

5

_why 还写了一篇很好的关于这个问题的文章: http://ruby-metaprogramming.rubylearning.com/html/seeingMetaclassesClearly.html - kejadlen

3
主题行与问题本身不太相符。我将回答主题行中表达的问题:
它们是同义词。
def self.foo
    ...
end

只是缩写形式

class << self
    def foo
        ...
    end
end

class << self 块中,您可以使用 privateprotected - weakish

2

你的结论是正确的。基本上,你需要记住,即使在Ruby中,类也是对象,因此具有实例。而且,通过使用class << self语句,您只是修改了该对象的类实例。


我刚刚修改了字符串类中的 "<< "运算符。现在我感觉自己很傻。它只是将字符串“class”与类名“self”连接起来,就像我在第一次声明类时所做的那样。我明白了。非常感谢! - fk2blow
1
什么鬼?这个解释完全荒谬。你说“在Ruby中,类是对象,因此有实例”,我想你的意思是说类本身就是实例吧?因为一个类拥有实例并不奇怪(那是类的本质)。此外,你还说“class << self”可以让你改变“对象的类实例”。什么鬼?这是什么意思?很抱歉,这个答案中的术语太奇怪了,我认为这表明了对问题的理解不完整。 - horseyguy
类是实例吗?我不确定谁的理解不完整。如果您能花时间提供一个不那么奇怪的答案来帮助我下次弄对它,那将非常有帮助。 - moritz
1
请查看我在答案中提供的链接,以深入了解当您执行“class << self”时实际发生了什么。 - kejadlen
@mortiz,请在下面回答。是的,类是实例(Class 和其元类的实例)的一种 ;) - horseyguy

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