Поиск…


Синтаксис

  • singleton_class = класс << объект; self end

замечания

В классах Singleton есть только один экземпляр: соответствующий ему объект. Это можно проверить, ObjectSpace Ruby:

instances = ObjectSpace.each_object object.singleton_class

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

Используя < , они также могут быть проверены как подклассы реального класса объекта:

object.singleton_class < object.class  # => true

Рекомендации:

Вступление

Ruby имеет три типа объектов:

  • Классы и модули, которые являются экземплярами класса Class или класса Module.
  • Экземпляры классов.
  • Одиночные классы.

Каждый объект имеет класс, который содержит его методы:

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 . Другие Example экземпляры не могут ответить на foo .

Ruby создает классы singleton по требованию. Доступ к ним или добавление к ним методов заставляют Ruby создавать их.

Доступ к Singleton Class

Существует два способа получить одноэлементный класс объекта

  • метод singleton_class .
  • Повторное открытие одноэлементного класса объекта и возвращение self .
object.singleton_class

singleton_class = class << object
  self
end

Доступ к переменным экземпляра / класса в классах Singleton

Одиночные классы делят свои переменные экземпляра / класса с их объектом.

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

Наследование класса Singleton

Подкласс также подклассы 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>

Расширение или включение модуля не расширяет Singleton Class

module ExampleModule
end

def ExampleModule.foo
  :foo
end

class Example
  extend ExampleModule
  include ExampleModule
end

Example.foo #=> NoMethodError: undefined method

Распространение сообщений с помощью класса Singleton

Экземпляры никогда не содержат метода, в котором они переносят данные. Однако мы можем определить одноэлементный класс для любого объекта, включая экземпляр класса.

Когда сообщение передается объекту (метод вызывается), 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

Повторное открытие (переключение обезьян) Singleton Classes

Существует три способа повторного открытия класса Singleton

  • Использование class_eval в одноэлементном классе.
  • Использование class << block.
  • Использование 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 каждый объект имеет несколько скрытый одноэлементный класс .

Это то, что позволяет определять методы для отдельных объектов. Класс singleton находится между самим объектом и его фактическим классом, поэтому все методы, определенные на нем, доступны для этого объекта и только для этого объекта.

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 :

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

До существования singleton_class как части основного API Ruby, одноэлементные классы были известны как метаклассы и могли быть доступны через следующую идиому:

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