ชั้น << สำนวนตัวเองในทับทิม


873

สิ่งที่ไม่class << selfทำในทับทิม ?


35
มีบทความที่ดีมากเกี่ยวกับหัวข้อนี้เขียนโดย Yehuda Katz: yehudakatz.com/2009/11/15/ … และ Yugui: yugui.jp/articles/846
Andrei

3
อีกประการหนึ่งที่ดีบทความซุปเปอร์ที่นี่: integralist.co.uk/posts/eigenclass.html
สมาน Mohamadi

2
ฉันเห็นสิ่งนี้ภายในโมดูลสิ่งนั้นทำให้แตกต่างหรือไม่? github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken

@FullDecent มันไม่ได้สร้างความแตกต่างเพราะทุกอย่างใน Ruby เป็นวัตถุรวมถึงโมดูลและคลาส
แอรอน

1
ดูgithub.com/defunkt/metaid/blob/master/metaid.rb มันไปกับ "เห็น Metaclasses ชัดเจน" viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html
Douglas G. Allen

คำตอบ:


912

ก่อนอื่นclass << fooไวยากรณ์จะเปิดfooคลาสเดี่ยวขึ้นมา(eigenclass) สิ่งนี้อนุญาตให้คุณชำนาญลักษณะการทำงานของวิธีการที่เรียกว่าบนวัตถุเฉพาะนั้น

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

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

ตอนนี้เพื่อตอบคำถาม: class << selfเปิดselfคลาส singleton ขึ้นเพื่อให้วิธีการสามารถกำหนดใหม่สำหรับselfวัตถุปัจจุบัน(ซึ่งภายในชั้นเรียนหรือร่างกายโมดูลเป็นชั้นเรียนหรือโมดูลตัวเอง ) โดยปกติจะใช้เพื่อกำหนดวิธีการเรียน / โมดูล ("คงที่"):

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

String.value_of 42   # => "42"

สิ่งนี้สามารถเขียนเป็นชวเลข:

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

หรือสั้นกว่า:

def String.value_of obj
  obj.to_s
end

เมื่ออยู่ภายในนิยามฟังก์ชันselfหมายถึงวัตถุที่ฟังก์ชันกำลังถูกเรียกด้วย ในกรณีนี้class << selfเปิดคลาส singleton สำหรับวัตถุนั้น สิ่งหนึ่งที่ใช้คือการใช้กลไกสถานะของชายยากจน:

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

ดังนั้นในตัวอย่างข้างต้นอินสแตนซ์ของแต่ละStateMachineExampleได้process_hookนามแฝงprocess_state_1แต่ทราบว่าในภายหลังก็สามารถ redefine process_hook(สำหรับselfเท่านั้นไม่ได้มีผลกระทบต่อคนอื่น ๆStateMachineExampleกรณี) process_state_2เพื่อ ดังนั้นทุกครั้งที่ผู้เรียกเรียกprocessเมธอด (ซึ่งเรียกการกำหนดนิยามใหม่process_hook) พฤติกรรมจะเปลี่ยนไปตามสถานะที่เป็นอยู่


22
@ Jörg: +1 สำหรับการแก้ไข (ฉันหวังว่า SO ให้ความสามารถในการ upvote แก้ไข; นั่นคือการใช้งานทั่วไปที่มากขึ้นclass << selfเพื่อสร้างวิธีการเรียน / โมดูล ฉันอาจจะขยายการใช้งานclass << selfเนื่องจากนั่นเป็นการใช้สำนวนที่มากขึ้น
Chris Jester-Young

4
gsub! ("eigenclass", "singleton class") ดูวิธีการที่จะเกิดขึ้นredmine.ruby-lang.org/repositories/revision/1?rev=27022
Marc-André Lafortune

4
มันสับสนจริง ๆ ที่อ้างถึงa's singleton_classเนื่องจากaคลาส (หลังจากเปลี่ยนinspect) เป็นตัวแปรที่แตกต่างกันของStringคลาส ถ้ามันเปลี่ยนStringคลาสซิงเกิลมันจะมีผลกับStringอินสแตนซ์อื่นทั้งหมด สิ่งที่น่าแปลกใจก็คือถ้าคุณเปิดใหม่Stringเพื่อกำหนดใหม่ในภายหลังinspectก็aจะยังคงรับการเปลี่ยนแปลงใหม่
โปรเก่า

1
@OldPro ฉันยังคงชอบชื่อ eigenclass เช่นเดียวกับ (ฉันเชื่อว่า) Matz แต่ฉันไม่สามารถทำให้ทุกคนพอใจได้
Chris Jester-Young

5
ฉันพบนิพจน์ "เปิดคลาส singleton ของวัตถุ" - ซึ่งฉันได้อ่านหลายครั้งก่อน - คลุมเครือ สำหรับความรู้ของฉันไม่มีที่ไหนในเอกสารทับทิมคือ "เปิด" ชั้นเรียนที่กำหนดแม้ว่าเราทุกคนมีความคิดในสิ่งที่มันหมายถึง มีความclass << selfหมายอะไรมากกว่าค่าที่selfตั้งไว้เท่ากับคลาสซิงเกิลภายในขอบเขตของบล็อกหรือไม่
Cary Swoveland

34

ผมพบว่าคำอธิบายที่ง่ายสุดเกี่ยวกับclass << self, Eigenclassและประเภทที่แตกต่างกันในวิธีการ

ใน Ruby มีวิธีการสามประเภทที่สามารถใช้กับคลาสได้:

  1. วิธีการอินสแตนซ์
  2. วิธีการเดี่ยว
  3. วิธีการเรียน

วิธีการตัวอย่างและวิธีการเรียนเกือบจะคล้ายกับ homonymous ในภาษาการเขียนโปรแกรมอื่น ๆ

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

อีกวิธีในการเข้าถึงEigenclass(ซึ่งรวมถึงวิธีการเดี่ยว) คือด้วยไวยากรณ์ต่อไปนี้ ( class <<):

foo = Foo.new

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

ตอนนี้คุณสามารถกำหนดวิธีการแบบซิงเกิลselfซึ่งเป็นคลาสFooในบริบทนี้:

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
จริง ๆ แล้ววิธีการเดี่ยวและวิธีการเรียนเหมือนกันทั้งสองวิธีนี้มีอยู่ในชั้นเรียนเดี่ยว คุณสามารถใช้foo.singleton_class.instance_methods(false)เพื่อตรวจสอบ
Damon Yuan

22

โดยปกติแล้ววิธีการอินสแตนซ์เป็นวิธีการทั่วโลก นั่นหมายความว่าพวกเขามีอยู่ในทุกกรณีของชั้นที่พวกเขาถูกกำหนด ในทางตรงกันข้ามวิธีการเดี่ยวจะดำเนินการในวัตถุเดียว

Ruby เก็บวิธีการในชั้นเรียนและวิธีการทั้งหมดจะต้องเชื่อมโยงกับชั้นเรียน วัตถุที่มีการกำหนดวิธีการแบบซิงเกิลไม่ใช่คลาส (เป็นอินสแตนซ์ของคลาส) ถ้าคลาสเท่านั้นที่สามารถเก็บวิธีการวัตถุจะเก็บวิธีเดียว? เมื่อมีการสร้างวิธีการแบบซิงเกิล Ruby จะสร้างคลาสแบบไม่ระบุชื่อโดยอัตโนมัติเพื่อเก็บวิธีการนั้น คลาสที่ไม่ระบุชื่อเหล่านี้เรียกว่า metaclasses หรือที่เรียกว่าคลาสเดี่ยวหรือ eigenclasses วิธีการแบบซิงเกิลมีความเกี่ยวข้องกับเมตาคลาสซึ่งในทางกลับกันจะเชื่อมโยงกับวัตถุที่มีการกำหนดวิธีการแบบซิงเกิล

หากมีการกำหนดวิธีการหลายวิธีแบบซิงเกิลภายในวัตถุเดียวทั้งหมดจะถูกเก็บไว้ใน metaclass เดียวกัน

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

ในตัวอย่างข้างต้นคลาส << z1 เปลี่ยนตัวตนปัจจุบันให้ชี้ไปที่ metaclass ของวัตถุ z1; จากนั้นมันจะกำหนดเมธอด say_hello ภายใน metaclass

คลาสยังเป็นวัตถุ (อินสแตนซ์ของคลาสในตัวที่เรียกว่าคลาส) วิธีการเรียนมีอะไรมากกว่าวิธีการเดียวที่เกี่ยวข้องกับวัตถุชั้นเรียน

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

วัตถุทั้งหมดอาจมี metaclasses นั่นหมายถึงคลาสสามารถมี metaclasses ในตัวอย่างด้านบนคลาส << self แก้ไขตนเองดังนั้นจึงชี้ไปที่ metaclass ของคลาส Zabuton เมื่อมีการกำหนดเมธอดโดยไม่มีตัวรับที่ชัดเจน (คลาส / วัตถุที่จะกำหนดเมธอด) มันจะถูกกำหนดโดยปริยายภายในขอบเขตปัจจุบันนั่นคือค่าปัจจุบันของตัวเอง ดังนั้นเมธอด stuff ถูกกำหนดภายในเมตาคลาสของคลาส Zabuton ตัวอย่างข้างต้นเป็นอีกวิธีหนึ่งในการกำหนดวิธีการเรียน IMHO เป็นการดีกว่าที่จะใช้ไวยากรณ์ def self.my_new_clas_method เพื่อกำหนดวิธีการเรียนเนื่องจากจะทำให้เข้าใจรหัสได้ง่ายขึ้น ตัวอย่างข้างต้นถูกรวมไว้เพื่อให้เราเข้าใจว่าเกิดอะไรขึ้นเมื่อเราเจอไวยากรณ์ของตัวเองในคลาส <<

ข้อมูลเพิ่มเติมสามารถพบได้ที่โพสต์นี้เกี่ยวกับการเรียนทับทิม


15

สิ่งที่คลาส << ทำอะไร:

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

[มันทำให้ ในบริบทของบล็อกของตน] self == thing.singleton_class


s.singleton_class คืออะไร

hi = String.new
def hi.a
end

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

hiวัตถุสืบทอด#methodsมาจากมัน#singleton_class.instance_methodsและจาก#class.instance_methodsนั้น
ที่นี่เราให้hiเป็นชั้นเดี่ยว:aวิธีการเช่น สามารถทำได้กับคลาส << สวัสดีแทน
hi's #singleton_classมีทุกวิธีการเช่นhi' s #classมีและอาจจะบางมากขึ้น ( :aที่นี่)

[วิธีการของสิ่งต่าง ๆ #class และ #singleton_class สามารถนำไปใช้โดยตรงกับสิ่งต่าง ๆ เมื่อ ruby ​​เห็นสิ่งของสิ่งแรกสุดจะค้นหา: นิยามเมธอดใน thing.singleton_class.instance_methods จากนั้นใน thing.class.instance_methods]


โดยวิธีการ - พวกเขาเรียกคลาส singletonของวัตถุ== metaclass == eigenclass


3

А วิธีเดี่ยวเป็นวิธีการที่กำหนดไว้เฉพาะสำหรับวัตถุเดียว

ตัวอย่าง:

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

วิธีการของ SingleClass ของ Singleton

ทดสอบ


วิธีการเดี่ยวของ test_obj

test_2

test_3


1

ในความเป็นจริงถ้าคุณเขียนส่วนขยาย C ใด ๆ สำหรับโครงการ Ruby ของคุณมีวิธีเดียวเท่านั้นในการกำหนดวิธีการโมดูล

rb_define_singleton_method

ฉันรู้ว่าธุรกิจตัวเองเพิ่งเปิดคำถามอื่น ๆ ทุกประเภทเพื่อให้คุณสามารถทำได้ดีขึ้นโดยการค้นหาแต่ละส่วน

วัตถุก่อน

foo = Object.new

ฉันจะทำวิธีการ foo ได้ไหม?

แน่ใจ

def foo.hello
 'hello'
end

ฉันจะทำอย่างไรกับมัน?

foo.hello
 ==>"hello"

แค่อีกวัตถุหนึ่ง

foo.methods

คุณได้รับวิธีการวัตถุทั้งหมดรวมทั้งวิธีการใหม่ของคุณ

def foo.self
 self
end

foo.self

เพียงแค่วัตถุ foo

ลองดูว่าจะเกิดอะไรขึ้นถ้าคุณทำ foo จากวัตถุอื่น ๆ เช่น Class และ Module ตัวอย่างจากคำตอบทั้งหมดเป็นสิ่งที่น่าเล่น แต่คุณต้องทำงานกับความคิดหรือแนวคิดที่แตกต่างกันเพื่อทำความเข้าใจสิ่งที่เกิดขึ้นกับวิธีการเขียนโค้ด ดังนั้นตอนนี้คุณมีคำศัพท์มากมายให้ดู

Singleton, Class, Module, self, Object และ Eigenclass ถูกนำขึ้นมา แต่ Ruby ไม่ได้ตั้งชื่อโมเดลของวัตถุในแบบนั้น มันเหมือน Metaclass มากขึ้น Richard หรือ __why แสดงแนวคิดให้คุณที่นี่ http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html และถ้าเสียงระเบิดออกไปให้ลองค้นหา Ruby Object Model ในการค้นหา วิดีโอสองเรื่องที่ฉันรู้จักบน YouTube คือ Dave Thomas และ Peter Cooper พวกเขาพยายามอธิบายแนวคิดนั้นด้วย เดฟใช้เวลานานกว่าจะได้มันจึงไม่ต้องกังวล ฉันยังคงทำงานกับมันเช่นกัน ทำไมฉันจะอยู่ที่นี่อีก ขอบคุณสำหรับคำถามของคุณ ยังดูที่ห้องสมุดมาตรฐาน มันมีโมดูล Singleton เช่นเดียวกับ FYI

อันนี้ค่อนข้างดี https://www.youtube.com/watch?v=i4uiyWA8eFk

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.