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

रूबी में अपवादों के लिए एक शुरुआती गाइड

दूसरे दिन मैं शुरुआती लोगों के लिए लिखे गए रूबी अपवादों का परिचय खोज रहा था - वे लोग जो मूल रूबी सिंटैक्स को जानते हैं लेकिन वास्तव में यह सुनिश्चित नहीं हैं कि अपवाद क्या है या यह क्यों उपयोगी है। मुझे एक नहीं मिला, इसलिए मैंने खुद इस पर जाने का फैसला किया। मुझे उम्मीद है कि आप इसे उपयोगी पाएँ। यदि कोई ऐसा बिंदु है जो भ्रमित करने वाला है, तो बेझिझक मुझे @StarrHorne पर ट्वीट करें। :)

अपवाद क्या है?

अप्रत्याशित घटनाओं से निपटने के लिए रूबी के तरीके अपवाद हैं।

यदि आपने कभी अपने कोड में कोई टाइपो बनाया है, जिससे आपका प्रोग्राम SyntaxError जैसे संदेश के साथ क्रैश हो जाता है या NoMethodError , तो आपने कार्रवाई में अपवाद देखे हैं।

जब आप रूबी में अपवाद उठाते हैं, तो दुनिया रुक जाती है और आपका प्रोग्राम बंद होना शुरू हो जाता है। यदि कुछ भी प्रक्रिया को रोकता नहीं है, तो आपका प्रोग्राम अंततः एक त्रुटि संदेश के साथ बाहर निकल जाएगा।

यहाँ एक उदाहरण है। नीचे दिए गए कोड में, हम शून्य से विभाजित करने का प्रयास करते हैं। यह असंभव है, इसलिए रूबी एक अपवाद उठाती है जिसे ZeroDivisionError . कहा जाता है . प्रोग्राम एक त्रुटि संदेश को छोड़ता है और प्रिंट करता है।

1 / 0
# Program crashes and outputs: "ZeroDivisionError: divided by 0"

क्रैशिंग प्रोग्राम हमारे उपयोगकर्ताओं को नाराज़ करते हैं। इसलिए हम आम तौर पर इस शटडाउन प्रक्रिया को रोकना चाहते हैं, और समझदारी से त्रुटि पर प्रतिक्रिया करना चाहते हैं।

इसे "बचाव," "हैंडलिंग," या "कैचिंग" एक अपवाद कहा जाता है। उन सबका मतलब एक ही है। रूबी में आप इसे इस तरह से करते हैं:

begin
  # Any exceptions in here... 
  1/0
rescue
  # ...will cause this code to run
  puts "Got an exception, but I'm responding intelligently!"
  do_something_intelligent()
end

# This program does not crash.
# Outputs: "Got an exception, but I'm responding intelligently!"

अपवाद अभी भी होता है, लेकिन यह प्रोग्राम को क्रैश नहीं करता है क्योंकि इसे "बचाया गया" था। रूबी बाहर निकलने के बजाय बचाव ब्लॉक में कोड चलाता है, जो एक संदेश को प्रिंट करता है।

यह अच्छा है, लेकिन इसकी एक बड़ी सीमा है। यह हमें बताए बिना "कुछ गलत हो गया" बताता है क्या गड़बड़ हो गया।

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

अपवाद वस्तुएं

अपवाद वस्तुएं सामान्य रूबी वस्तुएं हैं। आपके द्वारा अभी-अभी बचाए गए अपवाद के लिए वे "क्या हुआ" के बारे में सभी डेटा रखते हैं।

अपवाद ऑब्जेक्ट प्राप्त करने के लिए, आप थोड़ा अलग बचाव सिंटैक्स का उपयोग करेंगे।

# Rescues all errors, an puts the exception object in `e`
rescue => e

# Rescues only ZeroDivisionError and puts the exception object in `e`
rescue ZeroDivisionError => e

ऊपर के दूसरे उदाहरण में, ZeroDivisionError e . में ऑब्जेक्ट का वर्ग है . हमने जिन सभी "प्रकारों" के अपवादों के बारे में बात की है, वे वास्तव में सिर्फ वर्ग के नाम हैं।

अपवाद ऑब्जेक्ट्स में उपयोगी डीबग डेटा भी होता है। आइए हमारे ZeroDivisionError . के अपवाद ऑब्जेक्ट पर एक नज़र डालें ।

begin
  # Any exceptions in here... 
  1/0
rescue ZeroDivisionError => e
  puts "Exception Class: #{ e.class.name }"
  puts "Exception Message: #{ e.message }"
  puts "Exception Backtrace: #{ e.backtrace }"
end

# Outputs:
# Exception Class: ZeroDivisionError
# Exception Message: divided by 0
# Exception Backtrace: ...backtrace as an array...

अधिकांश रूबी अपवादों की तरह, इसमें अपने वर्ग के नाम के साथ एक संदेश और एक बैकट्रेस होता है।

अपना खुद का अपवाद उठाना

अभी तक हमने केवल अपवादों को बचाने के बारे में बात की है। आप अपने स्वयं के अपवादों को भी ट्रिगर कर सकते हैं। इस प्रक्रिया को "उठाना" कहा जाता है। आप इसे raise . पर कॉल करके करते हैं तरीका।

जब आप अपने स्वयं के अपवादों को उठाते हैं, तो आपको यह चुनना होता है कि किस प्रकार के अपवाद का उपयोग करना है। आपको त्रुटि संदेश भी सेट करना होगा।

यहां एक उदाहरण दिया गया है:

begin
  # raises an ArgumentError with the message "you messed up!"
  raise ArgumentError.new("You messed up!")
rescue ArgumentError => e  
  puts e.message
end

# Outputs: You messed up! 

जैसा कि आप देख सकते हैं, हम एक नया एरर ऑब्जेक्ट बना रहे हैं (एक ArgumentError ) एक कस्टम संदेश के साथ ("आपने गड़बड़ कर दी!") और इसे raise . पर भेज दिया विधि।

यह रूबी है, raise कई तरीकों से बुलाया जा सकता है:

# This is my favorite because it's so explicit
raise RuntimeError.new("You messed up!")

# ...produces the same result
raise RuntimeError, "You messed up!"

# ...produces the same result. But you can only raise 
# RuntimeErrors this way
raise "You messed up!"

कस्टम अपवाद बनाना

रूबी के अंतर्निर्मित अपवाद बहुत अच्छे हैं, लेकिन वे हर संभव उपयोग के मामले को कवर नहीं करते हैं।

क्या होगा यदि आप एक उपयोगकर्ता प्रणाली का निर्माण कर रहे हैं और जब उपयोगकर्ता साइट के ऑफ-लिमिट भाग तक पहुंचने का प्रयास करता है तो अपवाद उठाना चाहते हैं? रूबी के मानक अपवादों में से कोई भी फिट नहीं है, इसलिए आपकी सबसे अच्छी शर्त एक नए प्रकार का अपवाद बनाना है।

एक कस्टम अपवाद बनाने के लिए, बस एक नया वर्ग बनाएं जो StandardError . से विरासत में मिला हो .

class PermissionDeniedError < StandardError

end

raise PermissionDeniedError.new()

यह सिर्फ एक सामान्य रूबी वर्ग है। इसका मतलब है कि आप किसी भी अन्य वर्ग की तरह इसमें तरीके और डेटा जोड़ सकते हैं। आइए "कार्रवाई" नामक एक विशेषता जोड़ें:

class PermissionDeniedError < StandardError

  attr_reader :action

  def initialize(message, action)
    # Call the parent's constructor to set the message
    super(message)

    # Store the action in an instance variable
    @action = action
  end

end

# Then, when the user tries to delete something they don't
# have permission to delete, you might do something like this:
raise PermissionDeniedError.new("Permission Denied", :delete)

कक्षा पदानुक्रम

हमने अभी-अभी StandardError . को उपवर्गित करके एक कस्टम अपवाद बनाया है , जो स्वयं Exception . को उपवर्गित करता है .

वास्तव में, यदि आप रूबी में किसी अपवाद के वर्ग पदानुक्रम को देखते हैं, तो आप पाएंगे कि यह अंततः Exception पर वापस जाता है . यहाँ, मैं इसे आपको साबित करूँगा। ये रूबी के अधिकांश अंतर्निर्मित अपवाद हैं, जिन्हें पदानुक्रम में प्रदर्शित किया जाता है:

Exception
 NoMemoryError
 ScriptError
   LoadError
   NotImplementedError
   SyntaxError
 SignalException
   Interrupt
 StandardError
   ArgumentError
   IOError
     EOFError
   IndexError
   LocalJumpError
   NameError
     NoMethodError
   RangeError
     FloatDomainError
   RegexpError
   RuntimeError
   SecurityError
   SystemCallError
   SystemStackError
   ThreadError
   TypeError
   ZeroDivisionError
 SystemExit

बेशक, आपको इन सभी को याद रखने की जरूरत नहीं है। मैं उन्हें आपको दिखा रहा हूं क्योंकि पदानुक्रम का यह विचार एक विशिष्ट कारण से बहुत महत्वपूर्ण है।

किसी विशिष्ट वर्ग की त्रुटियों को दूर करने से उसके बाल वर्गों की त्रुटियों को भी बचाया जा सकता है।

आइए फिर से कोशिश करते हैं...

जब आप rescue StandardError , आप न केवल वर्ग StandardError . के साथ अपवादों का बचाव करते हैं लेकिन उनके बच्चों के भी। यदि आप चार्ट को देखते हैं, तो आप देखेंगे कि यह बहुत कुछ है:ArgumentError , IOError , आदि

यदि आप rescue Exception . थे , आप हर एक अपवाद को बचाएंगे, जो एक बहुत बुरा विचार होगा

सभी अपवादों का बचाव (खराब तरीका)

यदि आप चिल्लाना चाहते हैं, तो स्टैक ओवरफ्लो पर जाएं और कुछ ऐसा कोड पोस्ट करें जो इस तरह दिखता है:

// Don't do this 
begin
  do_something()
rescue Exception => e
  ...
end

उपरोक्त कोड हर अपवाद को बचाएगा। ऐसा मत करो! यह आपके प्रोग्राम को अजीब तरीके से तोड़ देगा।

ऐसा इसलिए है क्योंकि रूबी त्रुटियों के अलावा अन्य चीजों के लिए अपवादों का उपयोग करती है। यह उनका उपयोग "सिग्नल" नामक ऑपरेटिंग सिस्टम से संदेशों को संभालने के लिए भी करता है। यदि आपने कभी किसी प्रोग्राम से बाहर निकलने के लिए "ctrl-c" दबाया है, तो आपने सिग्नल का उपयोग किया है। सभी अपवादों को दबा कर आप उन संकेतों को भी दबा देते हैं।

कुछ प्रकार के अपवाद भी हैं - जैसे सिंटैक्स त्रुटियां - जो वास्तव में आपके प्रोग्राम को क्रैश कर सकती हैं। यदि आप उन्हें दबा देते हैं, तो आप कभी नहीं जान पाएंगे कि आप कब टाइपो या अन्य गलतियाँ करते हैं।

सभी त्रुटियों से बचाव (सही तरीका)

वापस जाएं और वर्ग पदानुक्रम चार्ट को देखें और आप देखेंगे कि सभी त्रुटियां जिन्हें आप बचाना चाहते हैं वे StandardError के बच्चे हैं

इसका अर्थ है कि यदि आप "सभी त्रुटियों" से बचाव करना चाहते हैं तो आपको StandardError . को बचाना चाहिए ।

begin
  do_something()
rescue StandardError => e
  # Only your app's exceptions are swallowed. Things like SyntaxErrror are left alone. 
end

वास्तव में, यदि आप अपवाद वर्ग निर्दिष्ट नहीं करते हैं, तो रूबी मानती है कि आपका मतलब StandardError है

begin
  do_something()
rescue => e
  # This is the same as rescuing StandardError
end

विशिष्ट त्रुटियों से बचाव (सर्वोत्तम तरीका)

अब जब आप जानते हैं कि सभी त्रुटियों को कैसे बचाया जाए, तो आपको पता होना चाहिए कि यह आमतौर पर एक बुरा विचार है, एक कोड गंध, जिसे हानिकारक माना जाता है, आदि।

वे आम तौर पर एक संकेत हैं कि आप यह पता लगाने के लिए बहुत आलसी थे कि किन विशिष्ट अपवादों को बचाया जाना चाहिए। और वे लगभग हमेशा आपको परेशान करने के लिए वापस आएंगे।

इसलिए समय निकालें और इसे सही करें। बचाव विशिष्ट अपवाद।

begin
  do_something()
rescue Errno::ETIMEDOUT => e
  // This will only rescue Errno::ETIMEDOUT exceptions
end

आप एक ही बचाव खंड में कई प्रकार के अपवादों को भी बचा सकते हैं, इसलिए कोई बहाना नहीं। :)

begin
  do_something()
rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED => e
end

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

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

  1. रूबी में अपवादों में संदर्भ डेटा कैसे जोड़ें

    कभी-कभी मानक बैकट्रैक/त्रुटि संदेश कॉम्बो पर्याप्त नहीं होता है। त्रुटि के कारण का पता लगाने के लिए कभी-कभी आपको अतिरिक्त डेटा की आवश्यकता होती है। सौभाग्य से, रूबी में करना बहुत आसान है। त्रुटि संदेश को अनुकूलित करना अपनी त्रुटियों में प्रासंगिक जानकारी जोड़ने का सबसे आसान तरीका इसे अपवाद के संदेश

  1. रूबी में कार्यात्मक प्रोग्रामिंग (पूर्ण गाइड)

    हो सकता है कि आपने अभी कार्यात्मक प्रोग्रामिंग के बारे में सुना हो और आपके कुछ प्रश्न हों। लाइक... कार्यात्मक प्रोग्रामिंग वास्तव में क्या है? यह ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग से कैसे तुलना करता है? क्या आपको रूबी में कार्यात्मक प्रोग्रामिंग का उपयोग करना चाहिए? आइए मैं आपके लिए इन सवालों के जव