तकनीकी सामग्री

Go कार्यक्रम os.Exit या log.Fatal* का उपयोग करके तुरंत बाहर निकलने के लिए करते हैं ( panic का उपयोग करना कार्यक्रम को बाहर निकलने का सही तरीका नहीं है, कृपया panic का उपयोग न करें)।

केवल main() में os.Exit या log.Fatal* में से एक को ही कॉल करें। अन्य सभी फ़ंक्शन त्रुटियाँ कॉल करने के लिए कॉलर को वापस त्रुटियाँ भेजें।

सिफारिश नहीं:

func main() {
  body := readFile(path)
  fmt.Println(body)
}
func readFile(path string) string {
  f, err := os.Open(path)
  if err != nil {
    log.Fatal(err)
  }
  b, err := os.ReadAll(f)
  if err != nil {
    log.Fatal(err)
  }
  return string(b)
}

सिफारिश की गई है:

func main() {
  body, err := readFile(path)
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println(body)
}
func readFile(path string) (string, error) {
  f, err := os.Open(path)
  if err != nil {
    return "", err
  }
  b, err := os.ReadAll(f)
  if err != nil {
    return "", err
  }
  return string(b), nil
}

सिद्धांत रूप में, कई निकास बिंदुओं वाले कार्यक्रमों में कई समस्याएँ होती हैं:

  • अस्पष्ट नियंत्रण प्रवाह: कोई भी फ़ंक्शन कार्यक्रम से बाहर निकल सकता है, जिससे नियंत्रण प्रवाह को समझना कठिन हो जाता है।
  • परीक्षण करना कठिन: कार्यक्रम से बाहर निकलने वाले फ़ंक्शन भी उन्हें पुकारते हुए परीक्षण से बाहर निकल जाते हैं। इससे ये फ़ंक्शन परीक्षण करना कठिन बना देता है और go test द्वारा अभी तक नहीं चलाए गए अन्य परीक्षणों को छोड़ने का खतरा उत्पन्न होता है।
  • सफाई को छोड़ना: जब एक फ़ंक्शन कार्यक्रम से बाहर निकलता है, तो वह किसी भी तब्दीली हुई फ़ंक्शन कॉल को छोड़ देता है। इससे महत्वपूर्ण सफाई कार्यों को छोड़ने का खतरा बढ़ जाता है।

एक बारी निकास

यदि संभव हो, तो आपके main() फ़ंक्शन में अधिकतम एक os.Exit या log.Fatal का कॉल होना चाहिए। यदि कई त्रुटि स्थितियाँ हैं जिन्हें कार्यक्रम की निष्पादन आवश्यकता है, तो उस तारीके को एक अलग फ़ंक्शन में रखें और वहाँ से त्रुटि वापस भेजें। इससे main() फ़ंक्शन को छोटा कर दिया जाएगा और सभी महत्वपूर्ण व्यापारिक तार्किकता को अलग, परीक्षणीय फ़ंक्शन में डाल दिया जाएगा।

सिफारिश नहीं:

package main
func main() {
  args := os.Args[1:]
  if len(args) != 1 {
    log.Fatal("missing file")
  }
  name := args[0]
  f, err := os.Open(name)
  if err != nil {
    log.Fatal(err)
  }
  defer f.Close()
  // यदि हम इस पंक्ति के बाद log.Fatal को कॉल करते हैं
  // तो f.Close निष्पादित किया जाएगा।
  b, err := os.ReadAll(f)
  if err != nil {
    log.Fatal(err)
  }
  // ...
}

सिफारिश की गई है:

package main
func main() {
  if err := run(); err != nil {
    log.Fatal(err)
  }
}
func run() error {
  args := os.Args[1:]
  if len(args) != 1 {
    return errors.New("missing file")
  }
  name := args[0]
  f, err := os.Open(name)
  if err != nil {
    return err
  }
  defer f.Close()
  b, err := os.ReadAll(f)
  if err != nil {
    return err
  }
  // ...
}

उपरोक्त उदाहरण में log.Fatal का उपयोग किया गया है, लेकिन इस दिशा-निर्देश को os.Exit या os.Exit कॉल करने वाले किसी भी पुस्तकालय विधि पर भी लागू किया जा सकता है।

func main() {
  if err := run(); err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
  }
}

आप run() के हस्ताक्षर को आवश्यकतानुसार परिवर्तित कर सकते हैं। उदाहरण के लिए, यदि आपका कार्यक्रम निश्चित विफलता कोड के साथ बाहर निकलना आवश्यक होता है, तो run() त्रुटि के स्थान पर निष्पादन को लौटा सकता है। यह यह भी संभव करता है कि इकाई परीक्षण सीधे इस व्यवहार की पुष्टि कर सकें।

func main() {
  os.Exit(run(args))
}

func run() (exitCode int) {
  // ...
}

कृपया ध्यान दें कि इन उदाहरणों में उपयोग की जाने वाली run() फ़ंक्शन एक बाध्य नहीं है। run() फ़ंक्शन का नाम, हस्ताक्षरण और सेटअप लचीले होते हैं। इसके अलावा, आप:

  • अपारस्थित कमांड-लाइन तर्कार्थ (जैसे, run(os.Args[1:])) स्वीकार करें
  • मुख्य() में में कमांड-लाइन तर्कार्थों को अपारस्थित करें और उन्हें run को पार करें
  • एक विशेष त्रुटि प्रकार के साथ, बाहरी कोड के लिए निष्पादन को मुख्य() में वापस भेजें
  • कारोबारिक तार्किकता को एक विभिन्न स्तर पर रखें package main

इस दिशा-निर्देश में सिर्फ यह आवश्यक है कि main() में वास्तविक बाहर निकलने वाले प्रवाह के लिए एक स्थान हो।