使用 Ruby 中的 class << self

3
我将为您翻译关于 Ruby 中 "class << self" 的底层机制。我知道这是一个单例类定义,也知道如何使用它,但我想更深入地了解其工作原理。
以下是一个示例:
class Klass
  puts "#{self}" #=> Klass
  class << self
    puts "#{self}" #=> #<Class:Klass>
  end
end

puts Klass.class #=> Class
puts Klass.singleton_class #=> #<Class:Klass>

这些语句为什么会输出它们所输出的内容?ClassClass:Klass、class 和 singleton_class 有何区别?请解释一下。

请尝试访问 http://www.devalot.com/articles/2008/09/ruby-singleton。 - Yam Marcovic
3个回答

0
irb>
irb>
irb> class FightClub; def rule_1; 'You do not talk about FIGHT CLUB.'; end; end
=> nil
irb> club1=FightClub.new
=> #<FightClub:0x007fb4240c48d0>
irb> club2=FightClub.new
=> #<FightClub:0x007fb42394b770>
irb>
irb>
irb> def club2.rule_2; rule_1; end
=> nil
irb> club1.rule_1
=> "You do not talk about FIGHT CLUB."
irb> club1.rule_2
NoMethodError: undefined method `rule_2' for #<FightClub:0x007fb4240c48d0>
from (pry):6:in `__pry__'
irb>
irb> club2.rule_1
=> "You do not talk about FIGHT CLUB."
irb> club2.rule_2
=> "You do not talk about FIGHT CLUB."
irb>

到目前为止很简单..

irb>
irb> club1.class.__id__ # FightClub
=> 70205838357120
irb> club2.class.__id__ # FightClub
=> 70205838357120
irb>
irb>
irb> club2.singleton_class # eigenclass of this instance
=> #<Class:#<FightClub:0x007fb42394b770>>
irb> club1.singleton_class
=> #<Class:#<FightClub:0x007fb4240c48d0>>
irb> club1.class.__id__ == club2.class.__id__
=> true
irb> club1.singleton_class.__id__ == club2.singleton_class.__id__
=> false
irb> club1.singleton_class.superclass.__id__ == 
irb*          club2.singleton_class.superclass.__id__ # 70205838357120
=> true
irb>
irb>
irb> club1.singleton_class.instance_methods.select{|m| m.to_s.start_with?('rule')}
=> [:rule_1]
irb> club2.singleton_class.instance_methods.select{|m| m.to_s.start_with?('rule')}
=> [:rule_2, :rule_1]
irb>
irb> club1.singleton_methods
=> []
irb> club2.singleton_methods
=> [:rule_2]
irb>

如果还不清楚:

  • singleton_class 是实例的eigenclass。这里有一个很好的 eigenclass 解释
  • 任何实例方法(例如此示例中的rule_2)都是singleton_methods,并在eighenclass上创建。
  • 所有eigenclasses的superclass相同(并且= instance.class)。
  • 观点:因此,表示any_ruby_object类的Class实例实际上是any_ruby_object.singleton_class而不是any_ruby_object.class

无关但仅为了使其混淆:

irb> club2.methods.select{ |m| m.to_s.start_with?('rule') }
=> [:rule_2, :rule_1]
irb> club1.methods.select{ |m| m.to_s.start_with?('rule') }
=> [:rule_1]
irb>

如果你删掉所有的IRB噪音,代码会读起来更好。 - Sergio Tulentsev

0

单例类是一种特殊的类,仅存在于该类的实例中,因为即使类定义也是对象,它们的另一个术语是特有类。其中一种用途是定义“类级方法”或“类级实例变量”(与类变量不同),这些变量仅对定义它们的类实例可用。另一种思考特有类的方式是它是类的实例,因为我们知道,在 Ruby 中,所有东西都是对象。

这里有一篇由 Andrea Singh 写的文章,我已经读了很多次,试图理解它。它非常好地展示了通过特有类进行类方法分派的过程:

http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html

说实话,在stackoverflow上解释这个有点太抽象了,我认为你试着通过示例理解是正确的。只要记住,一直到BasicObject,它就像是对象套娃,而不是大象和乌龟!

-1

#<类:Klass>Class是同一个类Class的不同实例。


@Stefan 单例类是一个类。Klass.singleton_class.class # => Class - sawa
1
谢谢,@sawa,但它们之间有什么区别吗? - Sergey
@Sergey 正如我所写的,它们是不同的实例。就像 1 不等于 2 一样,它们也是不同的。 - sawa

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