एर

एरर में Go

2 अभ्यास

एरर के बारे में

एरर इंटरफेस

Go में एरर हैंडलिंग एक्सेप्शन के ज़रिए नहीं होती। इसके बजाय, एरर ऐसे टाइप की सामान्य वैल्यू होती हैं जो बिल्ट-इन error इंटरफेस को लागू करते हैं। error इंटरफेस बहुत ही सीमित है। इसमें सिर्फ एक मेथड है, Error(), जो एरर संदेश को स्ट्रिंग के रूप में लौटाता है।

type error interface {
  Error() string
}

जब भी आप कोई ऐसा फंक्शन बनाते हैं जिसे चलाते समय कोई एरर हो सकती है जिसे कॉल करने वाले तक पहुँचना है, तो आपको error को रिटर्न टाइप में से एक के रूप में शामिल करना होगा। अगर फंक्शन कई वैल्यू लौटाता है, तो परंपरा के मुताबिक error हमेशा अंतिम वैल्यू होती है।

func DoSomething() (int, error) {
  // ...
}

एक सामान्य एरर बनाना और लौटाना

एरर इंटरफेस को हमेशा खुद लागू करना ज़रूरी नहीं है। एक सामान्य एरर बनाने के लिए आप errors.New() फंक्शन इस्तेमाल कर सकते हैं, जो स्टैंडर्ड लाइब्रेरी के पैकेज errors का हिस्सा है। आपको बस एरर संदेश को स्ट्रिंग के रूप में पास करना होता है, और errors.New() ऐसी वैल्यू बना देता है जिसमें आपका संदेश होता है और जो error इंटरफेस को लागू करती है।

अगर फंक्शन कोई एरर लौटाता है, तो बाकी सभी रिटर्न पैरामीटर के लिए ज़ीरो वैल्यू लौटाना अच्छा तरीका है:

func DoSomething() (SomeStruct, int, error) {
  // ...
  return SomeStruct{}, 0, errors.New("failed to calculate result")
}
Caution

अगर कोई एरर है, तो यह नहीं मान लेना चाहिए कि सभी फंक्शन बाकी रिटर्न वैल्यू के लिए ज़ीरो वैल्यू लौटाते हैं। सबसे अच्छा तरीका यह मानना है कि एरर लौटने पर बाकी रिटर्न वैल्यू में से किसी का भी इस्तेमाल करना सुरक्षित नहीं है।

उदाहरण के लिए, मान लीजिए कोई फंक्शन किसी फाइल को पढ़ने की कोशिश कर रहा था और वह आधे भरे बाइट स्लाइस के साथ एक एरर लौटाता है। अगर आप अपने कोड में उस लौटाए गए बाइट स्लाइस का दोबारा इस्तेमाल करें और यह मान लें कि एरर आने की वजह से वह हमेशा खाली है, तो आपको कुछ बारीक बग मिल सकते हैं।

इसके सिर्फ उन मामलों में अपवाद हैं जहाँ फंक्शन के डॉक्युमेंटेशन में साफ़ लिखा हो कि एरर होने पर बाकी रिटर्न वैल्यू भी मायने रखती हैं। उदाहरण के लिए [बफर पर Write का डॉक्युमेंटेशन][buffer-write] देखिए।

ध्यान रखिए कि आप जो एरर संदेश देते हैं वह जितना हो सके उतना सटीक हो, क्योंकि एरर में डिफ़ॉल्ट रूप से कोई स्टैक ट्रेस नहीं होता। परंपरा के मुताबिक एरर संदेश छोटे अक्षर से शुरू होना चाहिए और उसके अंत में पूर्ण विराम नहीं होना चाहिए।

अगर आप ऐसी एरर का इस्तेमाल कई जगह करना चाहते हैं (या अपने पैकेज को इस्तेमाल करने वालों के लिए वह एरर उपलब्ध कराना चाहते हैं), तो आपको errors.New को सीधे लिखने के बजाय एरर के लिए एक वेरिएबल घोषित करना चाहिए। परंपरा के मुताबिक वेरिएबल का नाम Err या err से शुरू होना चाहिए (यह इस पर निर्भर करता है कि वह एक्सपोर्टेड है या नहीं)। ऐसे एरर वेरिएबलो को अक्सर सेंटिनल एरर कहा जाता है।

import "errors"

var ErrNotFound = errors.New("resource was not found")

func DoSomething() error {
  // ...
  return ErrNotFound
}

यह बताने के लिए कि फंक्शन चलते समय कोई एरर नहीं हुई, एरर के लिए nil लौटाइए:

func Foo() (int, error) {
  return 10, nil
}

एरर संदेश में वेरिएबल शामिल करना

अगर आपको कुछ वेरिएबल से ज़्यादा जटिल एरर संदेश बनाना है, तो आप स्ट्रिंग फॉर्मैटिंग का इस्तेमाल कर सकते हैं। इस काम के लिए Go में एक खास फंक्शन fmt.Errorf है। यह एरर संदेश की स्ट्रिंग बनाता है और एक एरर लौटाता है।

input := 123
action := "UPDATE"

err := fmt.Errorf("invalid input %d for action %s", input, action)
err.Error()
// => "invalid input 123 for action UPDATE"

एरर की जाँच

अगर आप किसी ऐसे फंक्शन को कॉल करते हैं जो एरर लौटाता है, तो आमतौर पर एरर वैल्यू को err नाम के वेरिएबल में रखा जाता है। फंक्शन के वास्तविक परिणाम का इस्तेमाल करने से पहले आपको जाँच लेना चाहिए कि कोई एरर नहीं हुई थी। एरर की nil से तुलना करने के लिए हम == और != का इस्तेमाल कर सकते हैं, और जब err nil न हो, तो हम जान जाते हैं कि कोई एरर हुई थी।

अपने कोड के "सफल रास्ते" को अंदर-अंदर नेस्ट करने से बचने के लिए एरर वाले मामलों को पहले हैंडल करना चाहिए, आमतौर पर शुरुआत में ही लौटा देकर। ज़्यादा जानकारी के लिए Mat Ryer का यह प्रसिद्ध लेख देखिए।

// Do this:
func myFunc() error {
  file, err := os.Open("./users.csv")
  if err != nil {
    return err
  }
  // do something with file
}

// Not this:
func myFunc() error {
  file, err := os.Open("./users.csv")
  if err != nil {
    // handle err
  } else {
    // do something with file
  }
}

// Also not this:
func myFunc() error {
  file, err := os.Open("./users.csv")
  if err == nil {
    // do something with file
  }
  // handle err
}

ज़्यादातर मामलों में एरर ऊपर दिए गए पहले उदाहरण की तरह फंक्शन स्टैक में ऊपर तक लौटाई जाती है। एरर को हैंडल करने का एक और तरीका यह हो सकता है कि आप उसे लॉग करें और कोई दूसरा काम करते रहें। अच्छा तरीका यह है कि एरर को या तो लौटाइए या लॉग कीजिए, दोनों नहीं।

चूँकि Go में ज़्यादातर फंक्शन एरर को रिटर्न वैल्यू में से एक के रूप में शामिल करते हैं, इसलिए Go कोड में हर जगह आपको if err != nil पैटर्न दिखेगा और आप उसका इस्तेमाल करेंगे।

कस्टम एरर टाइप

अगर आप चाहते हैं कि आपकी एरर में सिर्फ एरर संदेश की स्ट्रिंग से ज़्यादा जानकारी हो, तो आप एक कस्टम एरर टाइप बना सकते हैं। जैसा पहले बताया गया, Go में हर वह चीज़ एरर का काम कर सकती है जो error इंटरफेस को लागू करती है (यानी जिसमें Error() string मेथड हो)।

आमतौर पर कस्टम एरर टाइप बनाने के लिए struct का इस्तेमाल किया जाता है। परंपरा के मुताबिक कस्टम एरर टाइप के नाम के अंत में Error होना चाहिए। साथ ही, Error() string मेथड को पॉइंटर रिसीवर के साथ बनाना सबसे अच्छा है। इसका कारण जानने के लिए यह Stackoverflow कमेंट देखिए। ध्यान दीजिए कि इसका मतलब यह है कि आपको अपनी कस्टम एरर का पॉइंटर लौटाना होगा, वरना वह error के रूप में नहीं गिनी जाएगी, क्योंकि बिना पॉइंटर वाली वैल्यू में Error() string मेथड नहीं होता।

type MyCustomError struct {
  message string
  details string
}

func (e *MyCustomError) Error() string {
  return fmt.Sprintf("%s, details: %s", e.message, e.details)
}

func someFunction() error {
  // ...
  return &MyCustomError{
    message: "...",
    details: "...",
  }
}
GitHub के ज़रिए संपादित करें यह लिंक नई विंडो या टैब में खुलता है।

एरर सीखिए

अभ्यास लॉक है

एरर पर अभ्यास करने के लिए 4 और अभ्यास अनलॉक कीजिए