ٹیکنیکی مواد

گو پروگرامز os.Exit یا log.Fatal* کا استعمال فوراً ختم کرنے کے لئے کرتے ہیں (پروگرام کو ختم کرنے کا طریقہ 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() فنکشن میں صرف a زیادہ سے زیادہ ایک os.Exit یا log.Fatal کا کال ہونا چاہئے۔ اگر مختلف خرابی کی صورت میں ہوں جو پروگرام کو ختم کرنے کی ضرورت ہو تو، اس منطق کو ایک مخصوص فنکشن میں اور وہاں سے ارور ریٹرن کریں۔ یہ main() فنکشن کو مناسب استعمال اور تمام اہم تجارتی منطق کو ایک الگ، قابل ٹیسٹ فنکشن میں رکھ کر اچھا بنا دیتا ہے۔

ترجیح دی جانے والی ترتیب:

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` میں پاس کریں.
  • ختم کوڈ کو main() میں واپس ریٹرن کریں ایک کسٹم ارور ٹائپ کے ساتھ۔
  • تجارتی منطق کو package main مختلف ابستریشن لیول پر رکھیں۔

یہ مشورہ فقط یہ مطابقت پر حقوق گزار ہے کے main() میں فعلی ختم فلو کے لئے ایک جگہ ہونا چاہئے۔