Ruby中的单例类到底是什么?


85

Ruby中的单例类本身就是类吗?这是所有对象都属于“类”的原因吗?这个概念很模糊,但是我认为它与为什么我可以完全定义类方法有关(class foo; def foo.bar ...)。

Ruby中的单例类是什么?

Answers:


154

首先,一个简单的定义:单例方法是仅针对单个对象定义的方法。例:

irb(main):001:0> class Foo; def method1; puts 1; end; end
=> nil
irb(main):002:0> foo = Foo.new
=> #<Foo:0xb79fa724>
irb(main):003:0> def foo.method2; puts 2; end
=> nil
irb(main):004:0> foo.method1
1
=> nil
irb(main):005:0> foo.method2
2
=> nil
irb(main):006:0> other_foo = Foo.new
=> #<Foo:0xb79f0ef4>
irb(main):007:0> other_foo.method1
1
=> nil
irb(main):008:0> other_foo.method2
NoMethodError: undefined method `method2' for #<Foo:0xb79f0ef4>
        from (irb):8

实例方法是类的方法(即在类的定义中定义)。类方法是类Class实例上的单例方法-它们未在类的定义中定义。而是在对象的单例类上定义它们。

irb(main):009:0> Foo.method_defined? :method1
=> true
irb(main):010:0> Foo.method_defined? :method2
=> false

用语法打开对象的单例类class << obj。在这里,我们看到此单例类是定义单例方法的地方:

irb(main):012:0> singleton_class = ( class << foo; self; end )
=> #<Class:#<Foo:0xb79fa724>>
irb(main):013:0> singleton_class.method_defined? :method1
=> true
irb(main):014:0> singleton_class.method_defined? :method2
=> true
irb(main):015:0> other_singleton_class = ( class << other_foo; self; end )
=> #<Class:#<Foo:0xb79f0ef4>>
irb(main):016:0> other_singleton_class.method_defined? :method1
=> true
irb(main):017:0> other_singleton_class.method_defined? :method2
=> false

因此,向对象添加单例方法的另一种方法是在对象的单例类打开的情况下定义它们:

irb(main):018:0> class << foo; def method3; puts 3; end; end
=> nil
irb(main):019:0> foo.method3
3
=> nil
irb(main):022:0> Foo.method_defined? :method3
=> false

综上所述:

  • 方法必须始终属于一个类(或:是某个类的实例方法)
  • 普通方法属于它们所定义的类(即该类的实例方法)
  • 类方法只是一个的单例方法 Class
  • 对象的单例方法不是对象类的实例方法;相反,它们是对象的单例类的实例方法。

17
在我的墓碑上会说“ RIP RubySingleton。Pistos救了我的理智。”
rmcsharry '16

1
@sawa我感谢您所做编辑的意图,但是我认为它们对我的帖子的含义和传达方式的影响太大,因此我撤消了您的编辑。
Pistos

33

Ruby提供了一种定义特定于特定对象的方法的方法,这种方法称为Singleton方法。当在对象上声明单例方法时,Ruby会自动创建一个仅容纳单例方法的类。新创建的类称为Singleton类。


    foo = Array.new
    def foo.size
      "Hello World!"
    end
    foo.size  # => "Hello World!"
    foo.class # => Array
    #Create another instance of Array Class and call size method on it
    bar = Array.new
    bar.size  # => 0
Singleton类是特定于对象的匿名类,它会自动创建并插入到继承层次结构中。

singleton_methods 可以在对象上调用以获得对象上所有单例方法的名称列表。

    foo.singleton_methods  # => [:size]
    bar.singleton_methods  # => []

这篇文章确实帮助我了解了Ruby中的Singleton类,并提供了一个很好的代码示例。


4
尽管此答案已有一年多的历史了,并且该链接很有用,但是如果您在此处,此网站上发布答案的基本部分,或者删除帖子的风险会更好,请参阅FAQ,其中提到的答案“非常多”比链接”。如果愿意,您仍可以包括该链接,但仅作为“参考”。答案应该独立存在,不需要链接。
塔林

同意@bluefeet在这里
Saurabh

感谢@bluefeet,更新了答案以解决您的评论。
Bedasso 2015年


4

最实用/行动主义的思考方式(IMHO)是:作为继承链,或方法查找/解析顺序。这张照片可能会有所帮助

http://www.klankboomklang.com/2007/11/25/modules-part-i-enter-the-include-class/

这是1.9版,对比了内置类和用户定义类:我仍在消化这个类。

http://d.hatena.ne.jp/sumim/20080111/p1

另外,我认为该术语的混淆用法是“单个对象”,这是不同的概念。单例对象来自一个类,该类的构造函数/实例化方法被覆盖,因此您只能分配该类中的一个。


链接之一已死。另一个是日语!
Ulysse BN

0

用最简单的术语来说,单例类是特殊类的红宝石鞭子,用于承载在单个对象上定义的方法。在ruby中,可以在单个对象上定义方法,而该方法对于该对象是唯一的。例如,请考虑以下内容

class User; end
user = User.new
def user.age
  "i'm a unique method"
end
user1 = User.new 
user.age #"i'm a unique method"
user1.age # NoMethodError (undefined method `age' for #<User:0x0000559c66ab7338>)

从上面可以看到,user1对象没有响应“ age”方法,因为它是单例方法,这是在用户对象上唯一定义的方法。为此,ruby创建一个特殊的类(称为单例类或本征类)来承载此唯一方法。您可以通过执行以下操作来验证这一点:

user.singleton_class # #<Class:#<User:0x0000559c66b47c58>>

您还可以通过使用method对象找出定义了“ age”方法的位置,在这里询问ruby是否找到“ age”方法。当您执行此操作时,您将看到单例类具有该方法。

user_singleton_class = user.method(:age).owner # #<Class:#<User:0x0000559c66b47c58>>
user.method(:age).owner == user.singleton_class # true
user_singleton_class.instance_methods(false) # [:age]

还要注意,就单例类而言,单例方法实际上是它的实例方法。

user.singleton_methods == user_singleton_class.instance_methods(false) # true
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.