Ruby Language
シングルトンクラス
サーチ…
構文
- 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
foo
はobject
シングルトンクラスで定義されてい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
これは、 object
のsingleton_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