Rubyのシングルトンクラスとは正確には何ですか?


85

Rubyのシングルトンクラスはそれ自体がクラスですか?すべてのオブジェクトが「クラス」に属する理由ですか?概念はあいまいですが、クラスメソッドを定義できる理由と関係があると思います(class foo; def foo.bar ...)。

Rubyのシングルトンクラスとは何ですか?

回答:


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。ピストスが私の正気を救った」と書かれています。
rmcsharry 2016年

1
@sawa編集の意図に感謝しますが、投稿の意味やコミュニケーションが少し変わったように感じたので、編集をロールバックしました。
ピストス

33

Rubyは、特定のオブジェクトに固有のメソッドを定義する方法を提供します。このようなメソッドは、シングルトンメソッドと呼ばれます。オブジェクトでシングルトンメソッドを宣言すると、Rubyはシングルトンメソッドのみを保持するクラスを自動的に作成します。新しく作成されたクラスはシングルトンクラスと呼ばれます。


    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_methods オブジェクトで呼び出して、オブジェクトのすべてのシングルトンメソッドの名前のリストを取得できます。

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

この記事は、Rubyのシングルトンクラスを理解するのに本当に役立ちました。良いコード例があります。


4
この回答は1年以上前のものであり、リンクは役に立ちますが、回答の重要な部分をここ、このサイトに投稿するか、投稿のリスクが削除されるとよいでしょう。FAQを参照してください。リンクよりも」。必要に応じてリンクを含めることもできますが、これは「参照」としてのみです。答えは、リンクを必要とせずに自立する必要があります。
タリン

ここで@bluefeetに同意します
Saurabh

@bluefeetに感謝し、コメントに対応するために回答を更新しました。
ベダソ2015年


4

それを考える最も実用的/アクション指向の方法(IMHO)は、継承チェーン、またはメソッドのルックアップ/解決順序としてです。この写真は役立つかもしれません

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

これはr1.9であり、組み込みクラスとユーザー定義クラスを対比しています。私はまだこれを消化しています。

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

また、この用語の紛らわしい使用法は「シングルトンオブジェクト」であると思います。これは別の概念です。シングルトンオブジェクトは、コンストラクター/インスタンス化メソッドがオーバーライドされているクラスから取得されるため、そのクラスの1つだけを割り当てることができます。


リンクの1つが停止しています。そしてもう一つは日本人です!
ユリシーズBN19年

0

簡単に言うと、シングルトンクラスは、個々のオブジェクトで定義されたホストメソッドに組み込まれる特別なクラスです。ルビーでは、そのオブジェクトだけに固有の個々のオブジェクトにメソッドを定義することが可能です。たとえば、以下を検討してください

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は、この一意のメソッドをホストするために、シングルトンクラスまたはeigenclassと呼ばれる特別なクラスを作成します。これは、次の手順で確認できます。

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

メソッドオブジェクトを使用してメソッド「age」が定義されている場所を見つけることにより、ここで「age」メソッドが見つかるかどうかをrubyに尋ねることもできます。これを行うと、シングルトンクラスにそのメソッドがあることがわかります。

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.