sınıf << Ruby'de kendi kendine deyim


873

Ne gelmez class << selfyapmak Ruby ?


35
Bu konuda Yehuda Katz tarafından yazılmış çok güzel bir makale var: yehudakatz.com/2009/11/15/… ve Yugui: yugui.jp/articles/846
Andrei

3
Başka bir süper güzel Makale: integralist.co.uk/posts/eigenclass.html
Saman Mohamadi

2
Bunu bir modülün içinde görüyorum, bu farklı mı? github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken

@FullDecent Ruby'deki her şey modüller ve sınıflar içeren bir nesne olduğu için bir fark yaratmaz.
Aaron

Yanıtlar:


912

İlk olarak, class << foosözdizimi foosingleton sınıfını (eigenclass) açar . Bu, söz konusu nesne üzerinde çağrılan yöntemlerin davranışını özelleştirmenize olanak tanır.

a = 'foo'
class << a
  def inspect
    '"bar"'
  end
end
a.inspect   # => "bar"

a = 'foo'   # new object, new singleton class
a.inspect   # => "foo"

: Şimdi soruyu cevaplamak için class << selfaçılır selfyöntemler akım için yeniden tanımlanabilir böylece, 'in tekil sınıfını self(bir sınıf veya modül vücut içinde sınıf olan veya modülü nesne kendisini ). Genellikle, bu sınıf / modül ("statik") yöntemlerini tanımlamak için kullanılır:

class String
  class << self
    def value_of obj
      obj.to_s
    end
  end
end

String.value_of 42   # => "42"

Bu, steno olarak da yazılabilir:

class String
  def self.value_of obj
    obj.to_s
  end
end

Veya daha da kısa:

def String.value_of obj
  obj.to_s
end

Bir işlev tanımının içindeyken self, işlevin çağrıldığı nesneyi ifade eder. Bu durumda, class << selfo nesne için singleton sınıfını açar; bunun bir kullanımı fakir bir insanın devlet makinesini uygulamaktır:

class StateMachineExample
  def process obj
    process_hook obj
  end

private
  def process_state_1 obj
    # ...
    class << self
      alias process_hook process_state_2
    end
  end

  def process_state_2 obj
    # ...
    class << self
      alias process_hook process_state_1
    end
  end

  # Set up initial state
  alias process_hook process_state_1
end

Yani, yukarıdaki örnekte, her örneği StateMachineExampleolan process_hookdiğer adı process_state_1, ama ikincisi de, bu yeniden tanımlamak nasıl notu process_hook(için selfdiğer etkilemeyen, sadece StateMachineExamplekarşı örneklerini) process_state_2. Bu nedenle, bir çağıran processyöntemi her yeniden çağırdığında (yeniden tanımlanabilir çağrıyı çağırır process_hook), davranış, bulunduğu duruma bağlı olarak değişir.


22
@ Jörg: Düzenleme için +1 (Keşke SO, düzenlemeleri kaldırma yeteneğini sağlar; oh iyi). Aslında bu, class << selfsınıf / modül yöntemleri oluşturmak için daha yaygın bir kullanımdır . class << selfÇok daha deyimsel bir kullanım olduğu için muhtemelen bu kullanımı genişleteceğim .
Chris Jester-Young

4
gsub! ("eigenclass", "singleton class"), yaklaşan yönteme bakın redmine.ruby-lang.org/repositories/revision/1?rev=27022
Marc-André Lafortune

4
a'S singleton_classberi a' s sınıfına (değiştikten sonra inspect) Stringsınıfın benzersiz bir varyantı olduğunu söylemek gerçekten kafa karıştırıcı . Tekil Stringsınıf değiştiriyor olsaydı, diğer tüm Stringörnekleri etkilerdi. Ne hala daha tuhaf var daha sonra yeniden eğer olmasıdır Stringyeniden tanımlamak için inspectdaha sonra ahala yeni değişiklikleri toplayacak.
Old Pro

1
@OldPro Matz'in de yaptığı gibi hala eigenclass adını tercih ediyorum. Ama herkesi memnun edemiyorum, sanırım.
Chris Jester-Young

5
"Daha önce birçok kez okuduğum - belirsiz bir nesnenin singleton sınıfını açar" ifadesini buluyorum. Bildiğim kadarıyla, Ruby belgelerinin hiçbir yerinde, ne anlama geldiğine dair bir fikrimiz olsa bile, tanımlanan bir sınıfı "açmak" mümkün değildir. class << selfDeğerinin ötesinde self, blok kapsamındaki singleton sınıfına eşit olan bir şey ifade ediyor mu ?
Cary Swoveland

34

Ben yaklaşık süper basit bir açıklaması buldum class << self, Eigenclassve yöntemlerinin farklı türde.

Ruby'de, bir sınıfa uygulanabilecek üç tür yöntem vardır:

  1. Örnek yöntemleri
  2. Singleton yöntemleri
  3. Sınıf yöntemleri

Örnek yöntemleri ve sınıf yöntemleri, diğer programlama dillerindeki adlarıyla neredeyse benzerdir.

class Foo  
  def an_instance_method  
    puts "I am an instance method"  
  end  
  def self.a_class_method  
    puts "I am a class method"  
  end  
end

foo = Foo.new

def foo.a_singleton_method
  puts "I am a singletone method"
end

Bir Eigenclass(tekton yöntemlerini içeren) erişmenin başka bir yolu da aşağıdaki sözdizimidir ( class <<):

foo = Foo.new

class << foo
  def a_singleton_method
    puts "I am a singleton method"
  end
end

şimdi bu bağlamda selfsınıfın Fookendisi olan tekli bir yöntem tanımlayabilirsiniz :

class Foo
  class << self
    def a_singleton_and_class_method
      puts "I am a singleton method for self and a class method for Foo"
    end
  end
end

4
aslında Singleton yöntemleri ve Class yöntemleri aynıdır, her ikisi de singleton sınıfında bulunur. foo.singleton_class.instance_methods(false)kontrol etmek için kullanabilirsiniz .
Damon Yuan

22

Genellikle örnek yöntemleri global yöntemlerdir. Bu, tanımlandıkları sınıfın tüm örneklerinde mevcut oldukları anlamına gelir. Buna karşılık, tek bir nesneye tekil bir yöntem uygulanır.

Ruby yöntemleri sınıflarda saklar ve tüm yöntemler bir sınıfla ilişkilendirilmelidir. Tekton yönteminin tanımlandığı nesne bir sınıf değildir (bir sınıfın örneğidir). Yalnızca sınıflar yöntemleri depolayabilirse, bir nesne nasıl bir singleton yöntemini depolayabilir? Tekli bir yöntem oluşturulduğunda, Ruby otomatik olarak bu yöntemi saklamak için anonim bir sınıf oluşturur. Bu anonim sınıflara, tek sınıf veya öz sınıflar olarak da bilinen metasınıflar denir. Singleton yöntemi, singleton yönteminin tanımlandığı nesne ile ilişkili olan metasınıf ile ilişkilidir.

Tek bir nesne içinde birden çok tekli yöntem tanımlanmışsa, hepsi aynı metasınıfta saklanır.

class Zen
end

z1 = Zen.new
z2 = Zen.new

class << z1
  def say_hello
    puts "Hello!"
  end
end

z1.say_hello    # Output: Hello!
z2.say_hello    # Output: NoMethodError: undefined method `say_hello'…

Yukarıdaki örnekte, << z1 sınıfı, geçerli benliği z1 nesnesinin metasınıfına işaret edecek şekilde değiştirir; sonra metasınıf içindeki say_hello yöntemini tanımlar.

Sınıflar ayrıca nesnelerdir (yerleşik sınıfın Class adı verilen örnekleri). Sınıf yöntemleri, bir sınıf nesnesiyle ilişkili singleton yöntemlerinden başka bir şey değildir.

class Zabuton
  class << self
    def stuff
      puts "Stuffing zabuton…"
    end
  end
end

Tüm nesnelerin metasınıfları olabilir. Bu, sınıfların metasınıfları da olabileceği anlamına gelir. Yukarıdaki örnekte, sınıf << kendini değiştirir, böylece Zabuton sınıfının metasınıfına işaret eder. Bir yöntem açık bir alıcı olmadan tanımlandığında (yöntemin tanımlanacağı sınıf / nesne), geçerli kapsamda, yani kendiliğin geçerli değeri içinde dolaylı olarak tanımlanır. Bu nedenle, stuff yöntemi Zabuton sınıfının metasınıfında tanımlanır. Yukarıdaki örnek, sınıf yöntemini tanımlamanın başka bir yoludur. IMHO, kodun anlaşılmasını kolaylaştırdığı için sınıf yöntemlerini tanımlamak için def self.my_new_clas_method sözdizimini kullanmak daha iyidir. Yukarıdaki örnek dahil edildi, bu yüzden sınıf << kendi sözdizimiyle karşılaştığımızda ne olduğunu anlıyoruz.

Ek bilgiler bulunabilir Yakut Sınıflar hakkında bu yazı .


15

Sınıf << şey ne yapar:

class Hi
  self #=> Hi
  class << self #same as 'class << Hi'
    self #=> #<Class:Hi>
    self == Hi.singleton_class #=> true
  end
end

[ self == thing.singleton_class bloğu bağlamında yapar ] .


Thing.singleton_class dosyası nedir?

hi = String.new
def hi.a
end

hi.class.instance_methods.include? :a #=> false
hi.singleton_class.instance_methods.include? :a #=> true

hiNesne devralır Onun #methodsonun ile ilgili #singleton_class.instance_methodsve daha sonra onun arasından #class.instance_methods.
Burada verdi hi'ın tekil sınıf örneği yöntemini :a. Bunun yerine << hi sınıfı ile yapılabilirdi .
hi's #singleton_classtüm örnek yöntemleri vardır hi' s #classve muhtemelen biraz daha ( :aburada).

[nesnelerin örnek yöntemleri #class ve #singleton_class doğrudan nesneye uygulanabilir. ruby thing.a'yı gördüğünde, önce şunu arar: thing.singleton_class.instance_methods ve sonra thing.class.instance_methods'da bir yöntem tanımı


Bu arada - nesnenin singleton class == metaclass == eigenclass diyorlar .


3

Eşdeğerinde tekil yöntem tek bir nesne için yalnızca tanımlanan bir yöntemdir.

Misal:

class SomeClass
  class << self
    def test
    end
  end
end

test_obj = SomeClass.new

def test_obj.test_2
end

class << test_obj
  def test_3
  end
end

puts "Singleton's methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton's methods of test_obj"
puts test_obj.singleton_methods

Singleton'ın SomeClass yöntemleri

Ölçek


Singleton'ın test_obj yöntemleri

test_2

test_3


1

Aslında, Ruby projeleriniz için herhangi bir C uzantısı yazarsanız, bir Modül yöntemini tanımlamanın tek bir yolu vardır.

rb_define_singleton_method

Bu kendi işinin sadece her türlü soruyu açtığını biliyorum, böylece her bir parçayı arayarak daha iyisini yapabilirsiniz.

Önce nesneler.

foo = Object.new

Foo için bir yöntem yapabilir miyim?

Elbette

def foo.hello
 'hello'
end

Bununla ne yapacağım?

foo.hello
 ==>"hello"

Sadece başka bir nesne.

foo.methods

Tüm Object yöntemlerini ve yenisini alırsınız.

def foo.self
 self
end

foo.self

Sadece foo nesnesi.

Sınıf ve Modül gibi diğer Nesneler'den foo yaparsanız ne olduğunu görmeye çalışın. Tüm cevaplardan örnekler oynamak güzel ama kodun yazılma biçiminde neler olup bittiğini gerçekten anlamak için farklı fikirler veya konseptlerle çalışmanız gerekiyor. Şimdi bakmanız gereken birçok terim var.

Singleton, Class, Module, self, Object ve Eigenclass gündeme getirildi, ancak Ruby Nesne Modellerini bu şekilde adlandırmıyor. Daha çok Metaclass gibi. Richard veya __neden sana buradaki fikri neden gösterir. http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html Ve sizi uçurursa, aramada Ruby Nesne Modelini aramayı deneyin. YouTube'da bildiğim iki video Dave Thomas ve Peter Cooper. Bu kavramı da açıklamaya çalışıyorlar. Dave'in bunu alması uzun zaman aldı, bu yüzden endişelenme. Ben de hala üzerinde çalışıyorum. Neden başka burada olabilirim? Sorunuz için teşekkürler. Ayrıca standart kütüphaneye de bakınız. Tıpkı bir FYI gibi bir Singleton Modülüne sahiptir.

Bu oldukça iyi. https://www.youtube.com/watch?v=i4uiyWA8eFk

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.