ٹیکنیکی مواد
گو پروگرامز 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()
میں فعلی ختم فلو کے لئے ایک جگہ ہونا چاہئے۔