Що таке клас синглтон в рубіні?


85

Чи є клас-синглтон у Ruby класом сам по собі? Чи це причина, чому всі об'єкти належать до "класу?" Концепція нечітка , але я вважаю, що це пов’язано з тим, чому я взагалі можу визначити метод класу ( class foo; def foo.bar ...).

Що таке клас синглтон у Ruby?

Відповіді:


154

По-перше, трохи визначення: одиночний метод - це метод, який визначається лише для одного об’єкта. Приклад:

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екземплярі класу - вони не визначені у визначенні класу. Натомість вони визначаються для класу singleton об’єкта.

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

Підсумовуючи:

  • методи завжди повинні належати до класу (або: бути методами екземпляра якогось класу)
  • нормальні методи належать до класу, в якому вони визначені (тобто є методами екземпляра класу)
  • Методи класу - це просто одиночні методи a Class
  • одноелементні методи об'єкта не є методами екземпляра класу об'єкта; скоріше, вони є методами екземпляра класу синглтон об'єкта.

17
На моєму Надгробку написано: "RIP Ruby Singleton. Пістос врятував мій розум".
rmcsharry

1
@sawa Я ціную намір ваших редагувань, але я відчуваю, що вони занадто сильно змінюють зміст та повідомлення мого допису, тому я відкотив ваші редагування назад.
Пістос

33

Ruby забезпечує спосіб визначення методів, специфічних для певного об'єкта, і такі методи відомі як Singleton Methods. Коли хтось оголошує на об'єкті метод singleton, Ruby автоматично створює клас для зберігання лише методів singleton. Щойно створений клас називається 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 - це специфічний анонімний клас, який автоматично створюється та вставляється в ієрархію успадкування.

singleton_methods можна викликати на об'єкті, щоб отримати список імен для всіх синглтон-методів на об'єкті.

    foo.singleton_methods  # => [:size]
    bar.singleton_methods  # => []

Ця стаття справді допомогла мені зрозуміти класи Singleton у Ruby, і вона має хороший приклад коду.


4
Хоча ця відповідь більше року , і зв'язок корисно було б краще , якщо ви розмістите основні частини відповіді тут, на цьому сайті, або ваше повідомлення ризикує бути видалений см довідку , де він згадує відповіді, які «трохи - трохи більше , ніж посилання '. Ви все ще можете включити посилання, якщо хочете, але лише як "посилання". Відповідь повинна стояти сама по собі, не потребуючи посилання.
Тарин

погодьтеся з @bluefeet тут
Саураб

Дякую @bluefeet, оновив відповідь на ваш коментар.
Бедассо


4

Найпрагматичніший / орієнтований на дії спосіб думати про це (IMHO): це як ланцюжок успадкування або порядок пошуку / вирішення методів. Ця картинка може допомогти

http://www.klankboomklang.com/2007/11/25/modules-part-i-enter-the-include-class/

Це r 1.9, контрастні вбудовані та визначені користувачем класи: я все ще перетравлюю цей.

http://d.hatena.ne.jp/sumim/20080111/p1

Крім того, я вважаю заплутаним використанням цього терміна "Singleton object", що є іншим поняттям. Об'єкт-одиночка походить із класу, у якого перевизначений метод конструктора / екземпляра, так що ви можете виділити лише один із цього класу.


Одне з посилань мертве. А інший - японський!
Ulysse BN

0

Клас синглтон, найпростішим чином, це спеціальний клас, який рубіни створюють для розміщення методів, визначених для окремих об'єктів. У рубіні можна визначити методи окремих об’єктів, які є унікальними лише для цього об’єкта. Наприклад, розглянемо наступне нижче

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', оскільки це одномісний метод, метод, однозначно визначений на об'єкті користувача. Для цього рубін створює спеціальний клас, який називається одиночним класом, або власним класом, для розміщення цього унікального методу. Ви можете перевірити це, виконавши наступне:

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]

Також зауважте, що, наскільки йде клас singleton, односторонні методи насправді є його методами екземпляра.

user.singleton_methods == user_singleton_class.instance_methods(false) # true
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.