1 Golang میں defer فیچر کا تعارف

Go زبان میں، defer کا کہنا ہے کہ اس کے بعد والی فنکشن کال کو اس وقت تک موخر کر دیا جاتا ہے جب تک defer کا فنکشن ختم ہونے والا ہو۔ آپ اسے دوسری پروگرامنگ زبانوں میں finally بلاک کے مترادف سمجھ سکتے ہیں، لیکن defer کا استعمال مزید موزون اور یکتا ہے۔

defer کے استعمال کا فائدہ یہ ہے کہ اس کو استعمال کیا جا سکتا ہے تاکہ صفائی کی تسکینات جیسے کہ فائلوں کو بند کرنا، mutexes کی آزاد کرنا، یا بس ہی فنکشن کی مخرج وقت کی داخلی کو ریکارڈ کرنا کیا جا سکے۔ یہ پروگرام کو زیادہ مضبوط بناتا ہے اور استثنائی صورتحال کے ھنڈلنگ میں پروگرامنگ کا کام کم کرتا ہے۔ Go کی ڈیزائن فلسافہ میں، defer کے استعمال کو تجویز کیا گیا ہے کیونکہ یہ غلطیاں منظم کرتا ہے اور کوڈ کو قصر کرتا ہے، ساتھ ہی اجاگری مکمل کرنے، اور دیگر بعد کے عملات کو منظم کرتے ہوئے۔

defer کا کام کرنے کا اصول

2.1 defer کا بنیادی کام کرنے کا اصول

defer کا بنیادی کام کرنے کا اصول ہے کہ ہر موخر انتظاری کرنے والے فنکشن کو چھوہدر stack (last in, first out principle) کا استعمال کرتے ہیں۔ defer کا بیان کرنے والے سٹیشنٹ کے بعد والی فنکشن کال کو فوراً نہیں چلاتا۔ بلکہ، یہ اسے ایک علیحدہ اسٹیک میں ڈال دیتا ہے۔ صرف اس صورت میں جب باہری فنکشن واپسی کو جا رہا ہوتا ہے، یہ انتظاری فنکشن کو اسٹیک کی ترتیب میں چلاتا ہے، defer کا آخری سٹیک کے فنکشن کو پہلے چلاتا ہے۔

اس کے علاوہ، یہ ذکر کرنا موزوں ہے کہ defer کے بعد والی فنکشن میں پیرامیٹرز کا حساب اور مصرف defer کے دائیں وقت کی حالت میں ثابت ہوتا ہے، وہ واقعی اجراء میں نہیں۔

func example() {
    defer fmt.Println("world") // deferred
    fmt.Println("hello")
}

func main() {
    example()
}

اوپر دیا گیا کوڈ ایسا رزلٹ دیں گا:

hello
world

world قبل از سامنے آتا ہے کہ example فنکشن ختم ہوتا ہے، چاہے یہ کوڈ میں hello سے پہلے ہو یا بعد میں۔

2.2 متعدد defer سٹیشنٹس کا اجرائی ترتیب

جب فنکشن میں متعدد defer سٹیشنٹس ہوتے ہیں، تو وہ آخر سے آخر، پہلے سے پہلے اجراء ہوتے ہیں۔ یہ عموماً پیچیدہ صفائی منطق کو سمجھنے کے لیے بہت اہم ہوتا ہے۔ نیچے دیے گئے مثال کی صورت میں متعدد defer سٹیشنٹس کے اجرائی ترتیب کی وضاحت کرتے ہیں:

func multipleDefers() {
    defer fmt.Println("First defer")
    defer fmt.Println("Second defer")
    defer fmt.Println("Third defer")

    fmt.Println("Function body")
}

func main() {
    multipleDefers()
}

اس کوڈ کا اوٹ پٹ یہ ہوگا:

Function body
Third defer
Second defer
First defer

defer آخر سے آخر کے اصول کو مد نظر رکھتے ہوئے، چاہے "First defer" سب سے پہلے موخر باندھی گئی ہے، یہ سب سے آخری طور پر اجراء ہوگی۔

defer کی مختلف سی ناریوں میں استعمال

3.1 وسائل کا خاتمہ

Go زبان میں، defer سٹیشنٹ کو عموماً وسائل خاتمہ کے منظور کرنے کے لیے استعمال کیا جاتا ہے، جیسے فائل عملیات اور ڈیٹا بیس کنیکشن وغیرہ۔ defer یہی یہ یقینی بناتا ہے کہ فنکشن کو ختم کرنے کے بعد، موازنہ والے وسائل کو منظم طریقے سے ختم کیا جائے گا۔

فائل کاروائی کی مثال:

func ReadFile(filename string) {
    file, err := os.Open(filename)
    if err != nil {
        log.Fatal(err)
    }
    // فائل بند کرنے کو یقینی بنانے کے لیے defer استعمال کریں
    defer file.Close()

    // فائل کی پڑھائی کی عملیات منظم کریں...
}

اس مثال میں، جب os.Open فائل کو کھولتا ہے، تو موازنہ والی defer file.Close() سٹیشنٹ یہ یقین کرتا ہے کہ فائل سرسوں منظمی کی جائے گی اور فائل ہینڈل وسائل جاتے ہوئے ختم کیا جائے گا۔

ڈیٹابیس کنیکشن کی مثال:

func QueryDatabase(query string) {
    db, err := sql.Open("mysql", "user:password@/dbname")
    if err != nil {
        log.Fatal(err)
    }
    // defer استعمال کرکے یقینی بنائیں کہ ڈیٹابیس کنیکشن بند ہوجائے
    defer db.Close()

    // ڈیٹابیس کوئری عملیات منظم کریں...
}

ایسی طرح، defer db.Close() یہ یقینی بناتا ہے کہ QueryDatabase فنکشن چھوڑنے کے بعد ڈیٹابیس کنیکشن بند ہو گا، چاہے وجہ واپسی ہو یا استثنائی صورتحال کو دیکھتے ہیں۔

3.2 ہم زمانہ پروگرامنگ میں لاک عملیات

ہم زمانہ پروگرامنگ میں، میوٹیکس لاکس کو آزاد کرنے کا ایک اچھا طریقہ مشق ہے۔ یہ یہ یقینی بناتا ہے کہ لاک کو درست طریقے سے آزاد کیا جاتا ہے بعد از ظروری حصہ کو چلایا جائے، ایسی طرح دیڑلاکس سے گرسے ہونے سے چھٹکارا ملتا ہے۔

میوٹیکس لاک کا مثال:

var mutex sync.Mutex

func updateSharedResource() {
    mutex.Lock()
    // لاک کا موقع چھوڑنے کے لئے دیفر کا استعمال کریں
    defer mutex.Unlock()

    // مشترکہ وسائل میں ترمیم کریں...
}

چاہے مشترکہ وسائل کی ترمیم کامیاب ہو یا دوسری چیز میں گھٹنے کے باوجود، defer یہ یقینی بناتا ہے کہ Unlock() کو بلا جائے گا جس سے بقایا goroutines لاک حاصل کر سکتے ہیں۔

مشورہ: میوٹیکس لاک کی تفصیلی تشریحات مواقع کے بعد درست کی جائیں گی۔ دیفر کے استعمال کے درمیان کے اطلاقات سمجھنا اس لحاظ سے کافی ہے۔

3 عام پٹھیوں اور دیفر کے لئے غور کرنے والے امور

دیفر کا استعمال کرتے وقت، چونکہ کوڈ کی پڑھائی اور ہم آہنگی بہتر ہوتی ہے، لہذا کچھ پٹھیوں اور غور وغیرہ کا خیال کرنا بھی ضروری ہے۔

3.1 دیفر کی مدد سے فنکشن کے پیرامیٹر فوراً اندازہ لگایا جاتا ہے

func printValue(v int) {
    fmt.Println("Value:", v)
}

func main() {
    value := 1
    defer printValue(value)
    // `value` کی قیمت کو بدلنا پیرامیٹر جو دیفر میں بھیجا گیا ہے پر اثر نہیں ڈالے گا
    value = 2
}
// اوپر سے آؤٹپٹ "Value: 1" ہوگا

اگرچہ defer کے اظہار کے بعد value کی قیمت کا بدلنا ہو گیا ہے، پیرامیٹر جو printValue میں defer کے بعد بھیجا گیا ہے وہ پہلے ہی اندازہ لگا کر مقرر ہے، اس لئے باہر "Value: 1" ہوگا۔

3.2 لوپ کے اندر دیفر کا استعمال کرتے وقت احتیاط کریں

لوپ کی اندر دیفر کا استعمال، لوپ کے ختم ہونے سے پہلے منسلک وسائل کی رہائی نہیں کرنے کی وجہ سے وسائل کو رہا نہیں کرنا و نقصان یا استعمال سے باہر ہوسکتا ہے۔

3.3 "استعمال کے بعد رہائی" کا احتیاط کریں در متوازی پروگرامنگ

ہمزاد پروگرامنگ میں، دیفر کا استعمال کرتے وقت، یہ ضروری ہے کہ یقینی بنائیں کہ وسائل کو رہا کر دیا گیا ہے تو اس کے بعد تمام goroutines وسائل تک رسائی حاصل کرنے کی کوشش نہیں کریں گے، تاکہ واقعہ کی حالت سے بچا جائے۔

4. دیفر کے اظہارات کی اجراء کے ترتیب کا خیال کریں

دیفر کے اظہارات لیسٹ-اِن-فرسٹ (LIFO) کے اصول کا مطابق ہوتے ہیں، جس میں آخری دیفر جو اعلان کی گئی ہے وہ سب سے پہلے اجراء کی جائے گی۔

حل اور بہتری کا عمل:

  • ہمیشہ دیفر بیانات میں فنکشن پیرامیٹر کو بیان کرنے وقت کا اندازہ کرنا ضروری ہے۔
  • لوپ کی اندر دیفر کا استعمال کرتے ہوئے، گمنام فنکشنز یا وسائل کی رہائی کو صریح طریقے سے کال کرنا سمجھیں۔
  • متوازی ماحول میں، یقینی بنائیں کہ تمام goroutines اپنے عمل ختم کرنے کے بعد ہی دیفر کے ذریعے وسائل کو رہا کریں۔
  • ایسے فنکشنز لکھتے وقت جو میں کئی defer بیانات پر مشتمل ہوں، ان کی اجراء کی ترتیب اور منطق کو دھیان سے سوچیں۔

ان بہترین مشوروں کی پیروی سے زیادہ تر دشواریاں جو دیفر کا استعمال کرتے وقت پائی جاتی ہیں کو دور کرنا ممکن ہے اور Go کوڈ کو مضبوط اور قابل دیکھ بھال لکھنے میں کامیاب ہونے کا باعث بن سکتا ہے۔