サーチ…


構文

  • singleton_class =クラス<<オブジェクト;自己終わり

備考

シングルトンクラスは1つのインスタンスしか持たない:対応するオブジェクト。これは、RubyのObjectSpace照会することで確認できます。

instances = ObjectSpace.each_object object.singleton_class

instances.count            # => 1
instances.include? object  # => true

<を使用すると、オブジェクトの実際のクラスのサブクラスであることも確認できます。

object.singleton_class < object.class  # => true

参考文献:

前書き

Rubyには3種類のオブジェクトがあります:

  • ClassクラスまたはClassモジュールのインスタンスであるクラスとモジュール。
  • クラスのインスタンス。
  • シングルトンクラス。

各オブジェクトには、そのメソッドを含むクラスがあります。

class Example
end

object = Example.new

object.class  # => Example
Example.class # => Class
Class.class   # => Class

オブジェクト自体にはメソッドを含めることはできません。クラスだけがメソッドを含めることができます。しかし、シングルトンクラスでは、他のシングルトンクラスを含む任意のオブジェクトにメソッドを追加することは可能です。

def object.foo
  :foo
end
object.foo #=> :foo

fooobjectシングルトンクラスで定義されていobject 。他のExampleインスタンスはfoo返信することはできません。

Rubyは必要に応じてシングルトンクラスを作成します。それらにアクセスしたり、それらにメソッドを追加することで、Rubyはそれらを作成します。

シングルトンクラスへのアクセス

オブジェクトのシングルトンクラスを取得するには2つの方法があります

  • singleton_classメソッド。
  • オブジェクトのシングルトンクラスを再オープンし、 selfを返す
object.singleton_class

singleton_class = class << object
  self
end

シングルトンクラスのインスタンス/クラス変数へのアクセス

シングルトンクラスはインスタンス/クラス変数をオブジェクトと共有します。

class Example
  @@foo = :example
end

def Example.foo
  class_variable_get :@@foo
end

Example.foo #=> :example

class Example
  def initialize
    @foo = 1
  end

  def foo
    @foo
  end
end

e = Example.new

e.instance_eval <<-BLOCK
  def self.increase_foo
    @foo += 1
  end
BLOCK

e.increase_foo
e.foo #=> 2

ブロックは、インスタンス/クラス変数のターゲットを囲んで閉じます。 class_evalまたはinstance_evalブロックを使用してインスタンス変数またはクラス変数にアクセスすることはできません。文字列をclass_evalか、 class_variable_getを使用して問題を回避します。

class Foo
  @@foo = :foo
end

class Example
  @@foo = :example 

  Foo.define_singleton_method :foo do
    @@foo
  end
end

Foo.foo #=> :example

シングルトンクラスの継承

サブクラスもシングルトンクラスをサブクラス化する

class Example
end

Example.singleton_class #=> #<Class:Example>

def Example.foo
  :example
end

class SubExample < Example
end

SubExample.foo #=> :example

SubExample.singleton_class.superclass #=> #<Class:Example>

モジュールの拡張またはインクルードがシングルトンクラスを拡張しない

module ExampleModule
end

def ExampleModule.foo
  :foo
end

class Example
  extend ExampleModule
  include ExampleModule
end

Example.foo #=> NoMethodError: undefined method

シングルトンクラスによるメッセージ伝播

インスタンスには、データのみを運ぶ方法は含まれません。しかし、クラスのインスタンスを含む任意のオブジェクトに対してシングルトンクラスを定義できます。

メッセージがオブジェクトに渡されると(メソッドが呼び出されると)、Rubyは最初にそのオブジェクトにシングルトンクラスが定義されているかどうかをチェックし、そうでない場合はRubyがインスタンスのクラスの先祖チェーンをチェックしてそれを調べます。

class Example
  def foo
    :example
  end
end

Example.new.foo #=> :example

module PrependedModule
  def foo
    :prepend
  end
end

class Example
  prepend PrependedModule
end

Example.ancestors #=> [Prepended, Example, Object, Kernel, BasicObject]
e = Example.new
e.foo #=> :prepended

def e.foo
  :singleton
end

e.foo #=> :singleton

再オープン(モンキーパッチ)シングルトンクラス

シングルトンクラスを再オープンする3つの方法があります

  • シングルトンクラスでclass_evalを使用する。
  • class <<ブロックを使用しています。
  • defを使ってオブジェクトのシングルトンクラスのメソッドを直接定義する
class Example
end

Example.singleton_class.class_eval do
  def foo
    :foo
  end
end

Example.foo #=> :foo

class Example
end

class << Example
  def bar
    :bar
  end
end

Example.bar #=> :bar

class Example
end

def Example.baz
  :baz
end

Example.baz #=> :baz

すべてのオブジェクトにアクセスできるシングルトンクラスがあります

class Example
end
ex1 = Example.new
def ex1.foobar
  :foobar
end
ex1.foobar #=> :foobar

ex2 = Example.new
ex2.foobar #=> NoMethodError

シングルトンクラス

すべてのオブジェクトはクラスのインスタンスです。しかし、それはすべての真実ではありません。 Rubyでは、すべてのオブジェクトもやや隠れたシングルトンクラスを持っています。

これは個々のオブジェクトにメソッドを定義できるようにするものです。シングルトンクラスは、オブジェクト自体とその実際のクラスの間に置かれるため、そのオブジェクトで定義されているすべてのメソッドとそのオブジェクトのみが使用できます。

object = Object.new

def object.exclusive_method
  'Only this object will respond to this method'
end

object.exclusive_method
# => "Only this object will respond to this method"

Object.new.exclusive_method rescue $!
# => #<NoMethodError: undefined method `exclusive_method' for #<Object:0xa17b77c>>

上記の例は、 define_singleton_methodを使って書くことができdefine_singleton_method

object.define_singleton_method :exclusive_method do
  "The method is actually defined in the object's singleton class"
end

これは、 objectsingleton_classメソッドを定義するのと同じです:

# send is used because define_method is private
object.singleton_class.send :define_method, :exclusive_method do
  "Now we're defining an instance method directly on the singleton class"
end

RubyのコアAPIの一部としてsingleton_classが存在する前に、シングルトンクラスはメタクラスとして知られており、次のイディオムでアクセスできました:

class << object
  self  # refers to object's singleton_class
end


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow