Ruby'de singleton sınıfı tam olarak nedir?


85

Ruby'deki singleton sınıfı başlı başına bir sınıf mı? Tüm nesnelerin "sınıfa" ait olmasının nedeni bu mu? Kavram belirsiz , ancak bunun neden bir sınıf yöntemi tanımlayabildiğimle ilgisi olduğuna inanıyorum ( class foo; def foo.bar ...).

Ruby'deki singleton sınıfı nedir?

Yanıtlar:


154

İlk olarak, küçük bir tanım: tekil yöntem , yalnızca tek bir nesne için tanımlanan bir yöntemdir. Misal:

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

Örnek yöntemler, bir sınıfın yöntemleridir (yani, sınıfın tanımında tanımlanmıştır). Sınıf yöntemleri, Classbir sınıf örneğindeki tek yöntemlerdir - sınıfın tanımında tanımlanmamıştır. Bunun yerine, nesnenin tekil sınıfında tanımlanırlar .

irb(main):009:0> Foo.method_defined? :method1
=> true
irb(main):010:0> Foo.method_defined? :method2
=> false

Sözdizimi ile bir nesnenin singleton sınıfını açarsınız class << obj. Burada, bu singleton sınıfının singleton yöntemlerinin tanımlandığı yer olduğunu görüyoruz:

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

Dolayısıyla, bir nesneye tekil yöntemler eklemenin alternatif bir yolu, onları nesnenin tekil sınıfı açık olarak tanımlamak olacaktır:

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

Özetle:

  • yöntemler her zaman bir sınıfa ait olmalıdır (veya: bazı sınıfların örnek yöntemleri olmalıdır)
  • normal yöntemler tanımlandıkları sınıfa aittir (yani, sınıfın örnek yöntemleridir)
  • sınıf yöntemleri, yalnızca bir Class
  • Bir nesnenin tekil yöntemleri, nesne sınıfının örnek yöntemleri değildir; daha ziyade, nesnenin singleton sınıfının örnek yöntemleridir.

17
Mezar Taşımın üzerinde "Ruby Singleton RIP. Pistos akıl sağlığımı kurtardı" yazacak.
rmcsharry

1
@sawa Düzenlemelerinizin amacını takdir ediyorum, ancak gönderimin anlamını ve iletişimini biraz fazla değiştirdiklerini hissediyorum, bu yüzden düzenlemelerinizi geri aldım.
Pistos

33

Ruby, belirli bir nesneye özgü yöntemleri tanımlamak için bir yol sağlar ve bu tür yöntemler Tekli Yöntemler olarak bilinir. Bir nesne üzerinde bir tekil yöntem bildirildiğinde, Ruby otomatik olarak sadece tekli yöntemleri tutacak bir sınıf oluşturur. Yeni oluşturulan sınıfa Singleton Sınıfı denir.


    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 sınıfı, otomatik olarak oluşturulan ve miras hiyerarşisine eklenen, nesneye özgü anonim sınıftır.

singleton_methods Bir nesnedeki tüm tekil yöntemlerin adlarının listesini almak için bir nesneye çağrılabilir.

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

Bu makale Ruby'deki Singleton Sınıflarını anlamama gerçekten yardımcı oldu ve iyi bir kod örneğine sahip.


4
Bu yanıt bir yıldan eski olsa ve bağlantı yararlı olsa da, cevabın temel kısımlarını burada, bu sitede veya gönderinin silinme riskiyle paylaşmanız daha iyi olur. bir bağlantıdan '. İsterseniz bağlantıyı yine de ekleyebilirsiniz, ancak yalnızca bir 'referans' olarak. Cevap, bağlantıya ihtiyaç duymadan kendi başına kalmalıdır.
Taryn

@ bluefeet'e katılıyorum
Saurabh

Teşekkürler @ bluefeet, yorumunuzu ele almak için cevabı güncelledi.
Bedasso


4

Bunu düşünmenin (IMHO) en pragmatik / eylem odaklı yolu şudur: kalıtım zinciri veya yöntem arama / çözümleme sırası olarak. Bu resim yardımcı olabilir

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

Bu r 1.9, yerleşik ve kullanıcı tanımlı sınıfların zıtlığı: bunu hala sindiriyorum.

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

Ayrıca, terimin kafa karıştırıcı bir kullanımının farklı bir kavram olan "Singleton nesnesi" olduğunu düşünüyorum. Bir singleton nesnesi, yapıcı / anında oluşturucu yöntemi geçersiz kılınmış bir sınıftan gelir, böylece bu sınıftan yalnızca birini ayırabilirsiniz.


Bağlantılardan biri öldü. Diğeri de Japon!
Ulysse BN

0

En basit terimlerle bir singleton sınıfı, tek tek nesneler üzerinde tanımlanan yöntemleri barındırmak için özel bir sınıf yakut kırbaçlarıdır. Ruby'de, tek tek nesneler üzerinde, yalnızca o nesneye özgü yöntemler tanımlamak mümkündür. Örneğin aşağıdakileri düşünün

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

Yukarıda görebileceğiniz gibi, kullanıcı1 nesnesi 'yaş' yöntemine yanıt vermez, çünkü kullanıcı nesnesi üzerinde benzersiz olarak tanımlanan bir yöntem olan tekil yöntemdir. Bunun gerçekleşmesi için Ruby, bu benzersiz yöntemi barındırmak üzere singleton sınıfı veya eigenclass adı verilen özel bir sınıf oluşturur. Aşağıdakileri yaparak bunu doğrulayabilirsiniz:

user.singleton_class # #<Class:#<User:0x0000559c66b47c58>>

Ayrıca, 'yaş' yönteminin nerede tanımlandığını bulmak için yöntem nesnesini kullanarak Ruby'ye burada 'yaş' yönteminin bulunup bulunmadığını sorabilirsiniz. Bunu yaptığınızda, singleton sınıfının bu yönteme sahip olduğunu göreceksiniz.

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]

Ayrıca, bir singleton sınıfına göre, singleton yöntemlerinin aslında örnek yöntemler olduğunu unutmayın.

user.singleton_methods == user_singleton_class.instance_methods(false) # true
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.