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

लेक्सिकल स्कोपिंग और रूबी क्लास वेरिएबल्स

रूबी के वर्ग चर भ्रमित कर रहे हैं। यहां तक ​​​​कि विशेषज्ञ रूबी उपयोगकर्ताओं को भी उन्हें समझना मुश्किल हो सकता है। सबसे स्पष्ट उदाहरण जड़त्व से संबंधित है:

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

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


  1. रूबी में कस्टम अपवाद

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

  1. रूबी में पर्यावरण चर का उपयोग कैसे करें?

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

  1. रूबी में डेकोरेटर डिजाइन पैटर्न

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