Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

रूबी क्लास वेरिएबल और उनके स्कोप को समझें: एक स्पष्ट गाइड

रूबी के क्लास वेरिएबल भ्रमित करने वाले हैं। यहां तक कि विशेषज्ञ रूबी उपयोगकर्ता भी उन्हें सहज रूप से समझने में कठिनाई महसूस कर सकते हैं। सबसे स्पष्ट उदाहरण इनहेरिटेंस से संबंधित है:

class Fruit @@kind = nil def self.kind @@kind end end class Apple < Fruit @@kind = "apple" end Apple.kind # => "apple" Fruit.kind # => "आपल" 

चाइल्ड क्लास पर kind वेरिएबल को बदलने से यह पेरेंट पर भी बदल जाता है। यह बहुत गड़बड़ है। लेकिन भाषा को इसी तरह काम करना चाहिए। यह बहुत समय पहले स्मॉलटॉक की नकल करने के लिए किया गया एक डिज़ाइन निर्णय था।

यह और खराब होता है

क्लास वेरिएबल की अजीबता के अन्य उदाहरण हैं जो आर्किटेक्चरल विकल्पों की तुलना में कार्यान्वयन विचित्रताओं की तरह लगते हैं। आज मैं इनमें से एक के बारे में बात करने जा रहा हूँ जो मुझे दिलचस्प लगता है।

हम अब कोड के दो टुकड़ों की तुलना करने जा रहे हैं। वे ऐसे दिखते हैं जैसे उन्हें एक समान परिणाम देना चाहिए लेकिन वे नहीं देते।

हमारे पहले उदाहरण में हम एक क्लास वेरिएबल सेट करते हैं और इसे वापस करने के लिए एक मेथड बनाते हैं। यहां बिल्कुल कुछ भी फैंसी नहीं चल रहा है। और सब कुछ उम्मीद के मुताबिक काम करता है।

class Foo @@val = 1234 # This is shorthand for declaring a class method. class << self def val @@val end end end Foo.val # => 1234 

शायद आप नहीं जानते होंगे, लेकिन class << self को क्लास परिभाषा के अंदर होना जरूरी नहीं है। नीचे दिए गए उदाहरण में हमने इसे बाहर ले जाया है। एक क्लास मेथड जोड़ा जाता है लेकिन यह क्लास वेरिएबल तक नहीं पहुंच सकता।

class Bar @@val = 1234 end class << Bar def val @@val end end Bar.val # warning: class variable access from toplevel # NameError: uninitialized class variable @@val in Object 

जब हम अपने फंक्शन से क्लास वेरिएबल तक पहुंचने की कोशिश करते हैं तो हमें एक चेतावनी और एक अपवाद मिलता है। क्या हो रहा है?

लेक्सिकल स्कोप में प्रवेश

मैं तेजी से आश्वस्त होता जा रहा हूँ कि लेक्सिकल स्कोप रूबी के 99% अजीब और भ्रमित करने वाले पहलुओं का स्रोत है।

यदि आप इस शब्द से परिचित नहीं हैं, तो लेक्सिकल स्कोपिंग चीजों को इस आधार पर समूहित करने को संदर्भित करता है कि वे कोड में कहां दिखाई देते हैं, न कि इस आधार पर कि वे एक अमूर्त ऑब्जेक्ट मॉडल में कहां से संबंधित हैं। इसे केवल एक उदाहरण दिखाकर समझाना बहुत आसान है:

class B # x and y share the same lexical scope x = 1 y = 1 end class B # z has a different lexical scope from x and y, even though it's in the same class. z = 3 end 

क्लास लेक्सिकली निर्धारित है

तो लेक्सिकल स्कोप हमारे क्लास वेरिएबल उदाहरण में कैसे काम कर रहा है?

खैर, एक क्लास वेरिएबल को पुनः प्राप्त करने के लिए रूबी को यह जानना होगा कि इसे किस क्लास से प्राप्त करना है। यह क्लास खोजने के लिए लेक्सिकल स्कोपिंग का उपयोग करता है।

अगर हम काम करने वाले उदाहरण को अधिक ध्यान से देखें तो हम देखते हैं कि क्लास वेरिएबल तक पहुंचने वाला कोड क्लास परिभाषा के भीतर भौतिक रूप से है।

class Foo class << self def val # I'm lexically scoped to Foo! @@val end end end 

काम न करने वाले उदाहरण में, क्लास वेरिएबल तक पहुंचने वाला कोड लेक्सिकली क्लास के लिए स्कोप्ड नहीं है।

class << Bar def val # Foo is nowhere in sight. @@val end end 

लेकिन अगर यह लेक्सिकली क्लास के लिए स्कोप्ड नहीं है, तो यह किसके लिए स्कोप्ड है? रूबी जो चेतावनी प्रिंट करता है वह हमें एक सुराग देता है: warning: class variable access from toplevel।

काम न करने वाले उदाहरण में यह पता चलता है कि क्लास वेरिएबल टॉप-लेवल ऑब्जेक्ट के लिए लेक्सिकली स्कोप्ड है। यह कुछ वास्तव में अजीब व्यवहार का कारण बन सकता है।

उदाहरण के लिए, यदि हमने टॉप लेवल ऑब्जेक्ट के लिए लेक्सिकली स्कोप्ड कोड से क्लास वेरिएबल सेट करने की कोशिश की, तो क्लास वेरिएबल Object पर सेट हो जाता है।

class Bar end class << Bar def val=(n) # This code is lexically scoped to the top level object. # That means, that `@@val` will be set on `Object`, not `Bar` @@val = i end end Bar.val = 100 # Whaa? Object.class_variables # => [:@@foo] 

अधिक उदाहरण

क्लास के लेक्सिकल स्कोप के बाहर क्लास वेरिएबल को संदर्भित करने के बहुत सारे तरीके हैं। उन सभी से आपको परेशानी होगी।

आपके आनंद के लिए यहां कुछ उदाहरण हैं:

class Foo @@foo = :foo end # This won't work Foo.class_eval { puts @@foo } # neither will this Foo.send :define_method, :x do puts @@foo end # ..and you weren't thinking about using modules, were you? module Printable def foo puts @@foo end end class Foo @@foo = :foo include Printable end Foo.new.foo 

और अब आप जानते हैं कि हर कोई रूबी में क्लास वेरिएबल का उपयोग कभी न करने के लिए क्यों कहता है। :)


  1. Ruby में कस्टम अपवाद में महारत हासिल करें: एक चरण-दर-चरण गाइड Ruby में कस्टम अपवाद में महारत हासिल करें: एक चरण-दर-चरण गाइड

    Ruby में अपने स्वयं के अपवाद बनाना आसान है। बस इन चरणों का पालन करें: 1. एक नई क्लास बनाएं अपवाद क्लास हैं, Ruby में बाकी सब की तरह! एक नए प्रकार का अपवाद बनाने के लिए, बस एक क्लास बनाएं जो StandardError, या उसके बच्चों में से एक से इनहेरिट करती है। class MyError < StandardError end raise MyError

  1. रूबी में एनवायरनमेंट वेरिएबल्स मास्टर करें: एक व्यावहारिक मार्गदर्शिका रूबी में एनवायरनमेंट वेरिएबल्स मास्टर करें: एक व्यावहारिक मार्गदर्शिका

    एक एनवायरनमेंट वेरिएबल एक कुंजी/मान जोड़ी है, यह इस तरह दिखती है: KEY=VALUE हम इन वेरिएबल्स का उपयोग अपने कंप्यूटर में सभी प्रोग्राम्स के बीच कॉन्फ़िगरेशन विकल्प साझा करने के लिए करते हैं। यही कारण है कि यह सीखना महत्वपूर्ण है कि वे कैसे काम करते हैं और ENV विशेष वेरिएबल का उपयोग करके अपने रूबी प्

  1. रूबी ऑब्जेक्ट्स को डेकोरेटर पैटर्न से बढ़ाएं: एक व्यावहारिक गाइड रूबी ऑब्जेक्ट्स को डेकोरेटर पैटर्न से बढ़ाएं: एक व्यावहारिक गाइड

    डेकोरेटर डिज़ाइन पैटर्न क्या है? और आप इस पैटर्न का उपयोग अपने रूबी प्रोजेक्ट्स में कैसे कर सकते हैं? डेकोरेटर डिज़ाइन पैटर्न आपको क्लास को बदले बिना नई क्षमताएं जोड़कर एक ऑब्जेक्ट को बढ़ाने में मदद करता है। आइए एक उदाहरण देखें! लॉगिंग और प्रदर्शन इस उदाहरण में हम rest-client जैसे जेम का उपयोग करके