สิ่งที่ไม่class << self
ทำในทับทิม ?
สิ่งที่ไม่class << self
ทำในทับทิม ?
คำตอบ:
ก่อนอื่น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
) พฤติกรรมจะเปลี่ยนไปตามสถานะที่เป็นอยู่
class << self
เพื่อสร้างวิธีการเรียน / โมดูล ฉันอาจจะขยายการใช้งานclass << self
เนื่องจากนั่นเป็นการใช้สำนวนที่มากขึ้น
a
's singleton_class
เนื่องจากa
คลาส (หลังจากเปลี่ยนinspect
) เป็นตัวแปรที่แตกต่างกันของString
คลาส ถ้ามันเปลี่ยนString
คลาสซิงเกิลมันจะมีผลกับString
อินสแตนซ์อื่นทั้งหมด สิ่งที่น่าแปลกใจก็คือถ้าคุณเปิดใหม่String
เพื่อกำหนดใหม่ในภายหลังinspect
ก็a
จะยังคงรับการเปลี่ยนแปลงใหม่
class << self
หมายอะไรมากกว่าค่าที่self
ตั้งไว้เท่ากับคลาสซิงเกิลภายในขอบเขตของบล็อกหรือไม่
ผมพบว่าคำอธิบายที่ง่ายสุดเกี่ยวกับclass << self
, Eigenclass
และประเภทที่แตกต่างกันในวิธีการ
ใน Ruby มีวิธีการสามประเภทที่สามารถใช้กับคลาสได้:
วิธีการตัวอย่างและวิธีการเรียนเกือบจะคล้ายกับ 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
foo.singleton_class.instance_methods(false)
เพื่อตรวจสอบ
โดยปกติแล้ววิธีการอินสแตนซ์เป็นวิธีการทั่วโลก นั่นหมายความว่าพวกเขามีอยู่ในทุกกรณีของชั้นที่พวกเขาถูกกำหนด ในทางตรงกันข้ามวิธีการเดี่ยวจะดำเนินการในวัตถุเดียว
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 เพื่อกำหนดวิธีการเรียนเนื่องจากจะทำให้เข้าใจรหัสได้ง่ายขึ้น ตัวอย่างข้างต้นถูกรวมไว้เพื่อให้เราเข้าใจว่าเกิดอะไรขึ้นเมื่อเราเจอไวยากรณ์ของตัวเองในคลาส <<
ข้อมูลเพิ่มเติมสามารถพบได้ที่โพสต์นี้เกี่ยวกับการเรียนทับทิม
class Hi
self #=> Hi
class << self #same as 'class << Hi'
self #=> #<Class:Hi>
self == Hi.singleton_class #=> true
end
end
[มันทำให้ ในบริบทของบล็อกของตน] self == 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
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
А วิธีเดี่ยวเป็นวิธีการที่กำหนดไว้เฉพาะสำหรับวัตถุเดียว
ตัวอย่าง:
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
ในความเป็นจริงถ้าคุณเขียนส่วนขยาย 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