रूबी के वर्ग चर भ्रमित कर रहे हैं। यहां तक कि विशेषज्ञ रूबी उपयोगकर्ताओं को भी उन्हें समझना मुश्किल हो सकता है। सबसे स्पष्ट उदाहरण जड़त्व से संबंधित है:
class Fruit
@@kind = nil
def self.kind
@@kind
end
end
class Apple < Fruit
@@kind = "apple"
end
Apple.kind
# => "apple"
Fruit.kind
# => "apple"
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
और अब आप जानते हैं कि रूबी में क्लास वेरिएबल्स का उपयोग न करने के लिए हर कोई क्यों कहता है। :)