class << idiom mandiri di Ruby

873

Apa yang class << selfdilakukan di Ruby ?

Randand
sumber
35
Ada artikel yang sangat bagus tentang topik ini yang ditulis oleh Yehuda Katz: yehudakatz.com/2009/11/15/… dan Yugui: yugui.jp/articles/846
Andrei
3
Artikel super bagus lainnya di sini: integralist.co.uk/posts/eigenclass.html
Saman Mohamadi
2
Saya melihat ini di dalam modul, apakah itu membuatnya berbeda? github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken
@ FullDecent Tidak membuat perbedaan karena semua yang ada di Ruby adalah objek termasuk modul dan kelas.
Aaron

Jawaban:

912

Pertama, class << foosintaks membuka fookelas singleton (eigenclass). Ini memungkinkan Anda untuk mengkhususkan perilaku metode yang dipanggil pada objek tertentu.

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

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

Sekarang, untuk menjawab pertanyaan: class << selfmembuka selfkelas singleton, sehingga metode dapat didefinisikan ulang untuk selfobjek saat ini (yang di dalam kelas atau badan modul adalah kelas atau modul itu sendiri ). Biasanya, ini digunakan untuk mendefinisikan metode kelas / modul ("statis"):

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

String.value_of 42   # => "42"

Ini juga dapat ditulis sebagai steno:

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

Atau bahkan lebih pendek:

def String.value_of obj
  obj.to_s
end

Ketika di dalam definisi fungsi, selfmerujuk ke objek yang dipanggil fungsi. Dalam hal ini, class << selfbuka kelas tunggal untuk objek itu; satu kegunaannya adalah untuk mengimplementasikan mesin negara orang miskin:

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

Jadi, dalam contoh di atas, setiap contoh StateMachineExampletelah process_hookalias untuk process_state_1, namun catatan bagaimana di kedua, dapat mendefinisikan kembali process_hook(untuk selfsaja, yang tidak mempengaruhi lainnya StateMachineExamplecontoh) untuk process_state_2. Jadi, setiap kali penelepon memanggil processmetode (yang memanggil didefinisikan ulang process_hook), perilaku berubah tergantung pada keadaan apa itu.

Chris Jester-Young
sumber
22
@ Jörg: +1 untuk diedit (Saya berharap SO memberikan kemampuan untuk mengunggah hasil edit; oh well). Itu memang penggunaan yang lebih umum class << self, untuk membuat metode kelas / modul. Saya mungkin akan memperluas penggunaan itu class << self, karena itu adalah penggunaan yang jauh lebih idiomatis.
Chris Jester-Young
4
gsub! ("eigenclass", "kelas singleton"), lihat metode yang akan datang redmine.ruby-lang.org/repositories/revision/1?rev=27022
Marc-André Lafortune
4
Ini benar-benar membingungkan untuk menyebut a's singleton_classkarena a' kelas s (setelah mengubah inspect) adalah varian unik dari Stringkelas. Jika itu mengubah Stringkelas singleton itu akan mempengaruhi semua Stringcontoh lainnya . Yang lebih aneh lagi adalah bahwa jika nanti Anda membuka kembali Stringuntuk mendefinisikan ulang inspectmaka aakan tetap mengambil perubahan baru.
Old Pro
1
@ OldPro Saya masih lebih suka nama eigenclass, seperti (saya percaya) Matz juga. Tapi, tidak bisa menyenangkan semua orang, kurasa.
Chris Jester-Young
5
Saya menemukan ungkapan, "membuka kelas singleton objek" - yang saya baca berkali-kali sebelumnya - tidak jelas. Sepengetahuan saya, tidak ada dalam dokumen Ruby "membuka" kelas yang ditentukan, meskipun kita semua memiliki gagasan tentang apa artinya. Apakah ada class << selfartinya lebih dari nilai selfyang diset sama dengan kelas singleton dalam ruang lingkup blok?
Cary Swoveland
34

Saya menemukan penjelasan super sederhana tentang class << self, Eigenclassdan berbagai jenis metode.

Di Ruby, ada tiga jenis metode yang dapat diterapkan ke kelas:

  1. Metode instance
  2. Metode singleton
  3. Metode kelas

Metode instance dan metode kelas hampir mirip dengan homonim mereka dalam bahasa pemrograman lain.

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

Cara lain untuk mengakses Eigenclass(yang mencakup metode tunggal) adalah dengan sintaks berikut ( class <<):

foo = Foo.new

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

sekarang Anda dapat mendefinisikan metode singleton selfyang merupakan kelas Fooitu sendiri dalam konteks ini:

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
Saman Mohamadi
sumber
4
sebenarnya metode Singleton dan metode Kelas adalah sama, keduanya ada di kelas singleton. Anda dapat menggunakannya foo.singleton_class.instance_methods(false)untuk memeriksa.
Damon Yuan
22

Biasanya, metode instan adalah metode global. Itu berarti mereka tersedia dalam semua instance kelas di mana mereka didefinisikan. Sebaliknya, metode singleton diterapkan pada satu objek.

Ruby menyimpan metode dalam kelas dan semua metode harus dikaitkan dengan suatu kelas. Objek di mana metode singleton didefinisikan bukan kelas (itu adalah instance dari kelas). Jika hanya kelas yang dapat menyimpan metode, bagaimana suatu objek dapat menyimpan metode tunggal? Ketika metode singleton dibuat, Ruby secara otomatis membuat kelas anonim untuk menyimpan metode itu. Kelas anonim ini disebut metaclasses, juga dikenal sebagai kelas singleton atau eigenclasses. Metode singleton dikaitkan dengan metaclass yang, pada gilirannya, dikaitkan dengan objek di mana metode singleton didefinisikan.

Jika beberapa metode tunggal didefinisikan dalam satu objek, mereka semua disimpan dalam metaclass yang sama.

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'…

Dalam contoh di atas, kelas << z1 mengubah diri saat ini untuk menunjuk ke metaclass dari objek z1; kemudian, ia mendefinisikan metode say_hello dalam metaclass.

Kelas juga objek (turunan dari kelas yang disebut Kelas). Metode kelas tidak lebih dari metode tunggal yang terkait dengan objek kelas.

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

Semua objek mungkin memiliki metaclasses. Itu berarti kelas juga dapat memiliki metaclasses. Dalam contoh di atas, kelas << self memodifikasi diri sehingga menunjuk ke metaclass dari kelas Zabuton. Ketika suatu metode didefinisikan tanpa penerima yang eksplisit (kelas / objek tempat metode tersebut akan didefinisikan), itu didefinisikan secara implisit dalam lingkup saat ini, yaitu, nilai saat ini dari diri. Oleh karena itu, metode barang didefinisikan dalam metaclass dari kelas Zabuton. Contoh di atas hanyalah cara lain untuk mendefinisikan metode kelas. IMHO, lebih baik menggunakan sintaks def self.my_new_clas_method untuk mendefinisikan metode kelas, karena itu membuat kode lebih mudah dimengerti. Contoh di atas disertakan sehingga kami memahami apa yang terjadi ketika kami menjumpai kelas << sintaks diri.

Info tambahan dapat ditemukan di posting ini tentang Ruby Classes .

BrunoFacca
sumber
15

Kelas apa << yang dikerjakan:

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

[itu dibuat self == thing.singleton_class dalam konteks bloknya] .


Apa itu thing.singleton_class?

hi = String.new
def hi.a
end

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

hiobjek mewarisi #methodsdari #singleton_class.instance_methodsdan kemudian dari #class.instance_methods.
Di sini kita memberikan hi's kelas tunggal metode contoh :a. Itu bisa dilakukan dengan kelas << hai sebagai gantinya.
hiIni #singleton_classsemua contoh metode hi's #classmemiliki, dan mungkin lagi ( :adi sini).

[contoh metode hal #class dan #singleton_class dapat diterapkan langsung ke hal ketika ruby ​​melihat thing.a, ia pertama-tama mencari: definisi metode di thing.singleton_class.instance_methods dan kemudian di thing.class.instance_methods]


By the way - mereka memanggil kelas singleton objek == metaclass == eigenclass .

danau
sumber
3

А metode tunggal adalah metode yang didefinisikan hanya untuk satu objek.

Contoh:

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

Metode Singleton untuk SomeClass

uji


Metode Singleton tentang test_obj

test_2

test_3

artamonovdev
sumber
1

Bahkan jika Anda menulis ekstensi C untuk proyek Ruby Anda, hanya ada satu cara untuk mendefinisikan metode Modul.

rb_define_singleton_method

Saya tahu bisnis mandiri ini hanya membuka semua jenis pertanyaan lain sehingga Anda bisa melakukan yang lebih baik dengan mencari di setiap bagian.

Objek dulu.

foo = Object.new

Bisakah saya membuat metode untuk foo?

Tentu

def foo.hello
 'hello'
end

Apa yang harus saya lakukan dengannya?

foo.hello
 ==>"hello"

Hanya objek lain.

foo.methods

Anda mendapatkan semua metode Objek plus yang baru.

def foo.self
 self
end

foo.self

Hanya Obyek foo.

Cobalah untuk melihat apa yang terjadi jika Anda membuat foo dari Objek lain seperti Kelas dan Modul. Contoh-contoh dari semua jawaban bagus untuk dimainkan, tetapi Anda harus bekerja dengan ide atau konsep yang berbeda untuk benar-benar memahami apa yang terjadi dengan cara kode ditulis. Jadi sekarang Anda memiliki banyak persyaratan untuk dilihat.

Singleton, Class, Module, self, Object, dan Eigenclass dibesarkan tetapi Ruby tidak menyebut Model Object seperti itu. Ini lebih seperti Metaclass. Richard atau __why menunjukkan Anda ide di sini. http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html Dan jika pukulan Anda pergi maka cobalah mencari Model Obyek Ruby dalam pencarian. Dua video yang saya tahu di YouTube adalah Dave Thomas dan Peter Cooper. Mereka mencoba menjelaskan konsep itu juga. Butuh waktu lama untuk mendapatkannya, jadi jangan khawatir. Saya masih mengerjakannya juga. Kenapa lagi saya di sini? Terima kasih atas pertanyaan anda Lihat juga perpustakaan standar. Ini memiliki Modul Singleton seperti halnya FYI.

Ini cukup bagus. https://www.youtube.com/watch?v=i4uiyWA8eFk

Douglas G. Allen
sumber