Sök…


Syntax

  • singleton_class = klass << objekt; själv slut

Anmärkningar

Singleton-klasser har bara en instans: deras motsvarande objekt. Detta kan verifieras genom att fråga Ruby's ObjectSpace :

instances = ObjectSpace.each_object object.singleton_class

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

Med hjälp av < kan de också verifieras till att vara underklasser av objektets faktiska klass:

object.singleton_class < object.class  # => true

referenser:

Introduktion

Ruby har tre typer av objekt:

  • Klasser och moduler som är fall av klass Klass eller klassmodul.
  • Instanser av klasser.
  • Singleton klasser.

Varje objekt har en klass som innehåller dess metoder:

class Example
end

object = Example.new

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

Objekt själva kan inte innehålla metoder, bara deras klass kan. Men med singleton klasser är det möjligt att lägga till metoder till alla objekt inklusive andra singleton klasser.

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

foo definieras på singleton klass av object . Andra Example instanser kan inte svara på foo .

Ruby skapar singleton-klasser på begäran. Att komma åt dem eller lägga till metoder till dem tvingar Ruby att skapa dem.

Åtkomst till Singleton Class

Det finns två sätt att få en klass av ett objekt

  • singleton_class metod.
  • Återöppna singleton klass av ett objekt och återvända self .
object.singleton_class

singleton_class = class << object
  self
end

Få åtkomst till instans- / klassvariabler i Singleton-klasser

Singleton-klasser delar sina instanser / klassvariabler med sitt objekt.

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

Block stänger runt deras instans / klassvariabler. Åtkomst instans eller klassvariabler med hjälp av ett block i class_eval eller instance_eval är inte möjlig. Att class_eval en sträng till class_eval eller använda class_variable_get fungerar kring problemet.

class Foo
  @@foo = :foo
end

class Example
  @@foo = :example 

  Foo.define_singleton_method :foo do
    @@foo
  end
end

Foo.foo #=> :example

Inheritance of Singleton Class

Subclasses också Subclasses Singleton Class

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>

Att utvidga eller inkludera en modul förlänger inte Singleton Class

module ExampleModule
end

def ExampleModule.foo
  :foo
end

class Example
  extend ExampleModule
  include ExampleModule
end

Example.foo #=> NoMethodError: undefined method

Meddelandeförökning med Singleton Class

Instanser innehåller aldrig en metod som de bara bär data. Men vi kan definiera en singleton klass för alla objekt inklusive en instans av en klass.

När ett meddelande skickas till ett objekt (metod kallas) kontrollerar Ruby först om en singleton-klass är definierad för det objektet och om det kan svara på det meddelandet annars kontrollerar Ruby instans klassens förfäder kedja och går upp på det.

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

Återöppning (monkey patch) Singleton klasser

Det finns tre sätt att öppna en Singleton Class igen

  • Använda class_eval på en singleton klass.
  • Med hjälp av class << block.
  • Använd def att definiera en metod direkt i objektets singleton-klass
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

Varje objekt har en singleton-klass som du kan komma åt

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

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

Singleton klasser

Alla objekt är instanser av en klass. Men det är inte hela sanningen. I Ruby har varje objekt också en något dold singletonklass .

Det är detta som gör det möjligt att definiera metoder på enskilda objekt. Singleton-klassen sitter mellan själva objektet och dess faktiska klass, så alla metoder som definieras på det är tillgängliga för det objektet och endast det objektet.

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>>

Exemplet ovan kunde ha skrivits med define_singleton_method :

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

Vilket är detsamma som att definiera metoden på 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

Innan singleton_class som en del av Rubys kärn-API, var singleton-klasser kända som metaclasses och kunde nås via följande formspråk:

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


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow