Во-первых, небольшое определение: одноэлементный метод - это метод, который определен только для одного объекта. Пример:
irb(main):001:0> class Foo; def method1; puts 1; end; end
=> nil
irb(main):002:0> foo = Foo.new
=> #<Foo:0xb79fa724>
irb(main):003:0> def foo.method2; puts 2; end
=> nil
irb(main):004:0> foo.method1
1
=> nil
irb(main):005:0> foo.method2
2
=> nil
irb(main):006:0> other_foo = Foo.new
=> #<Foo:0xb79f0ef4>
irb(main):007:0> other_foo.method1
1
=> nil
irb(main):008:0> other_foo.method2
NoMethodError: undefined method `method2' for #<Foo:0xb79f0ef4>
from (irb):8
Методы экземпляра - это методы класса (т. Е. Определенные в определении класса). Методы класса являются одноэлементными методами Class
экземпляра класса - они не определены в определении класса. Вместо этого они определены в одноэлементном классе объекта.
irb(main):009:0> Foo.method_defined? :method1
=> true
irb(main):010:0> Foo.method_defined? :method2
=> false
Вы открываете одноэлементный класс объекта с помощью синтаксиса class << obj
. Здесь мы видим, что в этом одноэлементном классе определены одноэлементные методы:
irb(main):012:0> singleton_class = ( class << foo; self; end )
=> #<Class:#<Foo:0xb79fa724>>
irb(main):013:0> singleton_class.method_defined? :method1
=> true
irb(main):014:0> singleton_class.method_defined? :method2
=> true
irb(main):015:0> other_singleton_class = ( class << other_foo; self; end )
=> #<Class:#<Foo:0xb79f0ef4>>
irb(main):016:0> other_singleton_class.method_defined? :method1
=> true
irb(main):017:0> other_singleton_class.method_defined? :method2
=> false
Таким образом, альтернативным средством добавления одноэлементных методов к объекту было бы определение их с открытым одноэлементным классом объекта:
irb(main):018:0> class << foo; def method3; puts 3; end; end
=> nil
irb(main):019:0> foo.method3
3
=> nil
irb(main):022:0> Foo.method_defined? :method3
=> false
В итоге:
- методы всегда должны принадлежать к классу (или: быть методами экземпляра некоторого класса)
- обычные методы принадлежат классу, в котором они определены (т.е. являются методами экземпляра класса)
- методы класса - это просто одноэлементные методы
Class
- одиночные методы объекта не являются методами экземпляра класса объекта; скорее, они являются методами экземпляра одноэлементного класса объекта.
Ruby предоставляет способ определения методов, специфичных для конкретного объекта, и такие методы известны как методы Singleton. Когда объявляется одноэлементный метод для объекта, Ruby автоматически создает класс для хранения только одноэлементных методов. Вновь созданный класс называется Singleton Class.
Синглтон-класс - это анонимный класс для конкретного объекта, который автоматически создается и вставляется в иерархию наследования.foo = Array.new def foo.size "Hello World!" end foo.size # => "Hello World!" foo.class # => Array #Create another instance of Array Class and call size method on it bar = Array.new bar.size # => 0
singleton_methods
может быть вызван для объекта, чтобы получить список имен для всех одноэлементных методов объекта.foo.singleton_methods # => [:size] bar.singleton_methods # => []
Эта статья действительно помогла мне понять классы Singleton в Ruby, и в ней есть хороший пример кода.
источник
Просто обновите ответ @Pistos, начиная с версии 1.9.2 ruby добавляет новый синтаксис для получения одноэлементного класса
singleton_class = ( class << foo; self; end )
можно заменить на:
https://apidock.com/ruby/Object/singleton_class
источник
Самый прагматичный / ориентированный на действия способ думать об этом (IMHO): как цепочка наследования или порядок поиска / разрешения метода. Эта картинка может помочь
http://www.klankboomklang.com/2007/11/25/modules-part-i-enter-the-include-class/
Это версия 1.9, контрастирующая со встроенными и пользовательскими классами: я все еще перевариваю этот.
http://d.hatena.ne.jp/sumim/20080111/p1
Кроме того, я думаю, что использование термина «одиночный объект» сбивает с толку, а это совсем другое понятие. Одноэлементный объект происходит из класса, у которого переопределен метод конструктора / экземпляра, так что вы можете выделить только один из этого класса.
источник
Простыми словами, одноэлементный класс - это специальный класс ruby, предназначенный для размещения методов, определенных для отдельных объектов. В ruby можно определять методы для отдельных объектов, которые уникальны только для этого объекта. Например, рассмотрите следующее ниже
class User; end user = User.new def user.age "i'm a unique method" end user1 = User.new user.age #"i'm a unique method" user1.age # NoMethodError (undefined method `age' for #<User:0x0000559c66ab7338>)
Как вы можете видеть выше, объект user1 не отвечает на метод age, потому что это одноэлементный метод, метод, однозначно определенный для объекта пользователя. Для этого Ruby создает специальный класс, называемый singleton class, или eigenclass, для размещения этого уникального метода. В этом можно убедиться, выполнив следующие действия:
user.singleton_class # #<Class:#<User:0x0000559c66b47c58>>
Вы также можете спросить Ruby, найден ли здесь метод age, используя объект метода, чтобы узнать, где определен метод age. Когда вы это сделаете, вы увидите, что у класса singleton есть этот метод.
user_singleton_class = user.method(:age).owner # #<Class:#<User:0x0000559c66b47c58>> user.method(:age).owner == user.singleton_class # true user_singleton_class.instance_methods(false) # [:age]
Также обратите внимание, что что касается одноэлементного класса, одноэлементные методы на самом деле являются методами экземпляра.
user.singleton_methods == user_singleton_class.instance_methods(false) # true
источник