रूबी मैजिक के नए एपिसोड में आपका स्वागत है! इस महीने का संस्करण सभी मेटाक्लास के बारे में है, एक विषय जो दो डेवलपर्स (हाय मौड!) के बीच एक चर्चा से निकला है।
मेटाक्लास की जांच करके, हम सीखेंगे कि रूबी में क्लास और इंस्टेंस तरीके कैसे काम करते हैं। साथ ही, एक स्पष्ट "परिभाषित" पास करके एक विधि को परिभाषित करने और class << self
का उपयोग करके अंतर की खोज करें या instance_eval
. चलो चलें!
क्लास इंस्टेंस और इंस्टेंस मेथड्स
यह समझने के लिए कि रूबी में मेटाक्लास का उपयोग क्यों किया जाता है, हम यह जांच कर शुरू करेंगे कि इंस्टेंस- और क्लास विधियों के बीच क्या अंतर हैं।
रूबी में, एक वर्ग एक वस्तु है जो अन्य वस्तुओं को बनाने के लिए एक खाका को परिभाषित करती है। कक्षाएं परिभाषित करती हैं कि उस वर्ग के किसी भी उदाहरण पर कौन सी विधियां उपलब्ध हैं।
एक वर्ग के अंदर एक विधि को परिभाषित करना एक आवृत्ति विधि बनाता है उस वर्ग पर। उस वर्ग के भविष्य के किसी भी उदाहरण में वह विधि उपलब्ध होगी।
class User
def initialize(name)
@name = name
end
def name
@name
end
end
user = User.new('Thijs')
user.name # => "Thijs"
इस उदाहरण में, हम User
. नामक एक वर्ग बनाते हैं , एक उदाहरण विधि . के साथ नाम #name
जो उपयोगकर्ता का नाम लौटाता है। कक्षा का उपयोग करके, हम तब एक वर्ग उदाहरण . बनाते हैं और इसे user
. नाम के वेरिएबल में स्टोर करें . चूंकि User
User
. का एक उदाहरण है वर्ग, इसमें #name
. है विधि उपलब्ध है।
एक वर्ग अपनी इंस्टेंस विधियों को अपनी विधि तालिका . में संग्रहीत करता है . उस वर्ग का कोई भी उदाहरण इसकी कक्षा की विधि तालिका को संदर्भित करता है ताकि इसकी आवृत्ति विधियों तक पहुंच प्राप्त हो सके।
क्लास ऑब्जेक्ट
एक वर्ग विधि एक विधि है जिसे पहले एक उदाहरण बनाए बिना सीधे कक्षा में बुलाया जा सकता है। एक क्लास मेथड इसके नाम को self.
. के साथ प्रीफ़िक्स करके बनाया जाता है इसे परिभाषित करते समय।
एक वर्ग स्वयं एक वस्तु है। एक स्थिरांक वर्ग वस्तु को संदर्भित करता है, इसलिए इस पर परिभाषित वर्ग विधियों को अनुप्रयोग में कहीं से भी बुलाया जा सकता है।
class User
# ...
def self.all
[new("Thijs"), new("Robert"), new("Tom")]
end
end
User.all # => [#<User:0x00007fb01701efb8 @name="Thijs">, #<User:0x00007fb01701ef68 @name="Robert">, #<User:0x00007fb01701ef18 @name="Tom">]
self.
. के साथ परिभाषित तरीके -उपसर्ग वर्ग की विधि तालिका में नहीं जोड़े जाते हैं। इसके बजाय उन्हें कक्षा के मेटाक्लास में जोड़ा जाता है।
मेटाक्लास
एक वर्ग के अलावा, रूबी में प्रत्येक वस्तु में एक छिपा हुआ मेटाक्लास होता है। मेटाक्लास सिंगलेट हैं, जिसका अर्थ है कि वे एक ही वस्तु से संबंधित हैं। अगर आप किसी क्लास के कई इंस्टेंस बनाते हैं, तो वे एक ही क्लास शेयर करेंगे, लेकिन उनके पास अलग-अलग मेटाक्लास होंगे।
thijs, robert, tom = User.all
thijs.class # => User
robert.class # => User
tom.class # => User
thijs.singleton_class # => #<Class:#<User:0x00007fb71a9a2cb0>>
robert.singleton_class # => #<Class:#<User:0x00007fb71a9a2c60>>
tom.singleton_class # => #<Class:#<User:0x00007fb71a9a2c10>>
इस उदाहरण में, हम देखते हैं कि यद्यपि प्रत्येक वस्तु का वर्ग User
. है , उनके सिंगलटन वर्गों में अलग-अलग ऑब्जेक्ट आईडी होते हैं, जिसका अर्थ है कि वे अलग-अलग ऑब्जेक्ट हैं।
एक मेटाक्लास तक पहुंच प्राप्त करके, रूबी मौजूदा वस्तुओं में सीधे तरीके जोड़ने की अनुमति देता है। ऐसा करने से ऑब्जेक्ट की कक्षा में कोई नया तरीका नहीं जुड़ता।
robert = User.new("Robert")
def robert.last_name
"Beekman"
end
robert.last_name # => "Beekman"
User.new("Tom").last_name # => NoMethodError (undefined method `last_name' for #<User:0x00007fe1cb116408>)
इस उदाहरण में, हम एक #last_name
जोड़ते हैं robert
. में संग्रहीत उपयोगकर्ता के लिए चर। हालांकि robert
User
. का एक उदाहरण है , User
. के किसी भी नए बनाए गए उदाहरण #last_name
तक पहुंच नहीं होगी विधि, क्योंकि यह केवल robert
. पर मौजूद है का मेटाक्लास।
self
?
एक विधि को परिभाषित करते समय और एक रिसीवर को पास करते समय, नई विधि को रिसीवर के मेटाक्लास में जोड़ा जाता है, बजाय इसे क्लास की मेथड टेबल में जोड़ने के।
tom = User.new("Tom")
def tom.last_name
"de Bruijn"
end
ऊपर के उदाहरण में, हमने #last_name
. जोड़ा है सीधे tom
. पर ऑब्जेक्ट, tom
. पास करके विधि को परिभाषित करते समय रिसीवर के रूप में।
क्लास मेथड्स के लिए भी यह इसी तरह काम करता है।
class User
# ...
def self.all
[new("Thijs"), new("Robert"), new("Tom")]
end
end
यहां, हम स्पष्ट रूप से self
. पास करते हैं .all
. बनाते समय एक रिसीवर के रूप में तरीका। एक वर्ग परिभाषा में, self
वर्ग को संदर्भित करता है (User
इस मामले में), तो .all
विधि User
में जुड़ जाती है का मेटाक्लास।
क्योंकि User
एक स्थिरांक में संग्रहीत एक वस्तु है, जब भी हम इसका संदर्भ देते हैं, हम उसी वस्तु तक पहुँचते हैं—और उसी मेटाक्लास तक।
मेटाक्लास खोलना
हमने सीखा है कि क्लास मेथड क्लास ऑब्जेक्ट के मेटाक्लास में मेथड होते हैं। यह जानने के बाद, हम क्लास मेथड्स बनाने की कुछ अन्य तकनीकों को देखेंगे जिन्हें आपने पहले देखा होगा।
class << self
हालाँकि यह शैली से थोड़ा बाहर हो गया है, कुछ पुस्तकालय class << self
. का उपयोग करते हैं वर्ग विधियों को परिभाषित करने के लिए। यह सिंटैक्स ट्रिक वर्तमान वर्ग के मेटाक्लास को खोलती है और इसके साथ सीधे इंटरैक्ट करती है।
class User
class << self
self # => #<Class:User>
def all
[new("Thijs"), new("Robert"), new("Tom")]
end
end
end
User.all # => [#<User:0x00007fb01701efb8 @name="Thijs">, #<User:0x00007fb01701ef68 @name="Robert">, #<User:0x00007fb01701ef18 @name="Tom">]
यह उदाहरण User.all
. नामक एक वर्ग विधि बनाता है User
. में एक विधि जोड़कर का मेटाक्लास। जैसा कि हमने पहले देखा था, विधि के लिए स्पष्ट रूप से एक रिसीवर पास करने के बजाय, हम self
. सेट करते हैं User
. के लिए User
. के बजाय मेटाक्लास का मेटाक्लास स्वयं।
जैसा कि हमने पहले सीखा, स्पष्ट रिसीवर के बिना किसी भी विधि परिभाषा को वर्तमान वर्ग की एक उदाहरण विधि के रूप में जोड़ा जाता है। ब्लॉक के अंदर, वर्तमान वर्ग है User
का मेटाक्लास (#<Class:User>
)।
instance_eval
एक अन्य विकल्प instance_eval
. का उपयोग करना है , जो एक ही काम को एक बड़े अंतर के साथ करता है। हालांकि वर्ग का मेटाक्लास ब्लॉक में परिभाषित विधियों को प्राप्त करता है, self
मुख्य वर्ग का संदर्भ बना हुआ है।
class User
instance_eval do
self # => User
def all
[new("Thijs"), new("Robert"), new("Tom")]
end
end
end
User.all # => [#<User:0x00007fb01701efb8 @name="Thijs">, #<User:0x00007fb01701ef68 @name="Robert">, #<User:0x00007fb01701ef18 @name="Tom">]
इस उदाहरण में, हम User
. पर एक उदाहरण विधि परिभाषित करते हैं पहले की तरह ही मेटाक्लास है, लेकिन self
अभी भी User
. की ओर इशारा करता है . हालांकि यह आमतौर पर एक ही वस्तु की ओर इशारा करता है, "डिफ़ॉल्ट परिभाषित" और self
विभिन्न वस्तुओं को इंगित कर सकते हैं।
हमने क्या सीखा
हमने सीखा है कि केवल कक्षाएं ही ऐसी वस्तुएँ हैं जिनमें विधियाँ हो सकती हैं, और वह उदाहरण विधियाँ वास्तव में किसी वस्तु के मेटाक्लास पर विधियाँ हैं। हम जानते हैं कि class << self
बस self
को स्वैप करता है आपको मेटाक्लास पर विधियों को परिभाषित करने की अनुमति देने के लिए, और हम जानते हैं कि instance_eval
ज्यादातर वही काम करता है (लेकिन self
. को छुए बिना )।
यद्यपि आप स्पष्ट रूप से मेटाक्लास के साथ काम नहीं करेंगे, रूबी उन्हें हुड के नीचे बड़े पैमाने पर उपयोग करती है। जब आप किसी विधि को परिभाषित करते हैं तो क्या होता है, यह जानने से आपको यह समझने में मदद मिल सकती है कि रूबी ऐसा क्यों व्यवहार करती है (और आपको वर्ग विधियों को self.
के साथ उपसर्ग क्यों करना है। )।
पढ़ने के लिए धन्यवाद। यदि आप जो पढ़ते हैं उसे पसंद करते हैं, तो आप एक ई-मेल प्राप्त करने के लिए रूबी मैजिक की सदस्यता लेना पसंद कर सकते हैं जब हम महीने में एक बार एक नया लेख प्रकाशित करते हैं।