Ricerca…


Sintassi

  • singleton_class = class << object; fine di sé

Osservazioni

Le classi Singleton hanno solo un'istanza: il loro oggetto corrispondente. Questo può essere verificato interrogando Ruby's ObjectSpace :

instances = ObjectSpace.each_object object.singleton_class

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

Usando < , possono anche essere verificate come sottoclassi della classe effettiva dell'oggetto:

object.singleton_class < object.class  # => true

Riferimenti:

introduzione

Ruby ha tre tipi di oggetti:

  • Classi e moduli che sono istanze di classe Classe o modulo di classe.
  • Istanze di classi
  • Singleton Classes.

Ogni oggetto ha una classe che contiene i suoi metodi:

class Example
end

object = Example.new

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

Gli oggetti stessi non possono contenere metodi, solo la loro classe può. Ma con le classi singleton, è possibile aggiungere metodi a qualsiasi oggetto incluse altre classi di singleton.

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

foo è definito sulla classe di object singleton. Altri Example casi non possono rispondere a foo .

Ruby crea corsi singoli su richiesta. Accedervi o aggiungere metodi a loro forza costringe Ruby a crearli.

Accesso alla classe Singleton

Esistono due modi per ottenere la classe singleton di un oggetto

  • metodo singleton_class .
  • Riapertura della classe singleton di un oggetto e ritorno di self .
object.singleton_class

singleton_class = class << object
  self
end

Accesso alle variabili istanza / classe nelle classi Singleton

Le classi Singleton condividono le loro istanze / variabili di classe con il loro oggetto.

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

I blocchi si chiudono attorno alla loro variabile di istanza / classe target. Non è possibile accedere alle variabili di istanza o classe utilizzando un blocco in class_eval o instance_eval . Passare una stringa a class_eval o utilizzare class_variable_get il problema.

class Foo
  @@foo = :foo
end

class Example
  @@foo = :example 

  Foo.define_singleton_method :foo do
    @@foo
  end
end

Foo.foo #=> :example

Eredità della classe Singleton

Sottoclassi anche sottoclassi 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>

L'estensione o l'inclusione di un modulo non estende la classe Singleton

module ExampleModule
end

def ExampleModule.foo
  :foo
end

class Example
  extend ExampleModule
  include ExampleModule
end

Example.foo #=> NoMethodError: undefined method

Propagazione dei messaggi con la classe Singleton

Le istanze non contengono mai un metodo che portano solo dati. Tuttavia possiamo definire una classe singleton per qualsiasi oggetto che includa un'istanza di una classe.

Quando un messaggio viene passato a un oggetto (il metodo viene chiamato) Ruby controlla prima se una classe singleton è definita per quell'oggetto e se può rispondere a quel messaggio altrimenti Ruby verifica la catena di antenati della classe dell'istanza e ne va su.

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

Riapertura (scimmia rattoppando) Singleton Classes

Esistono tre modi per riaprire una classe Singleton

  • Usando class_eval su una classe singleton.
  • Usando il class << block.
  • Utilizzando def per definire direttamente un metodo sulla classe Singleton dell'oggetto
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

Ogni oggetto ha una classe singleton a cui è possibile accedere

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

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

Lezioni di Singleton

Tutti gli oggetti sono istanze di una classe. Tuttavia, non è tutta la verità. In Ruby, ogni oggetto ha anche una classe singleton un po 'nascosta.

Questo è ciò che consente di definire i metodi su singoli oggetti. La classe singleton si trova tra l'oggetto stesso e la sua classe effettiva, quindi tutti i metodi definiti su di esso sono disponibili per quell'oggetto e solo quell'oggetto.

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

L'esempio precedente potrebbe essere stato scritto usando define_singleton_method :

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

Il che equivale a definire il metodo sulla singleton_class object :

# 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

Prima dell'esistenza di singleton_class come parte dell'API core di Ruby, le classi singleton erano conosciute come metaclassi e potevano essere accessibili tramite il seguente idioma:

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


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow