الأساسيات

تأجيل الدوال defer

– ما معنى “تأجيل الدوال” ؟ Defer

تأجيل دالة يعني أننا نريد تنفيذ الدالة A ولكن فقط, وحصراً فقط, عندما ينتهي تنفيذ دالة B .
ويتم ذلك عبر استخدام الكلمة المفتاحية defer قبل اسم الدالة.

فمثلاً لنفرض أنه لدينا برنامج حيث يدخل المستخدم اسمه, وبعد ذلك يتم عرض رسالة ترحيبية (مثل: “مرحباً أحمد”) للمستخدم تتضمن الاسم الذي أدخله, وبعد الرسالة الترحيبية, نريد أن نظهر له رسالة توديعية (مثل “الى اللقاء”) وبعدها بثواني يتم اغلاق النافذة تلقائياً

أولاً, علينا أن نستدعي الحزم اللازمة للبرنامج,

import (
  "bufio"
  "fmt"
  "os"
  "time"
)

وثم ننشئ دالة الرسالة الترحيبية

func hello(name string){
	fmt.Println("\nHello, ",name)
	defer bye()
}

الدالة hello تتلقى متغير name وثم تقوم بعرض رسالة ترحيبية متضمنةً الاسم, وثم نقوم بالإعلان عن الدالة المؤجلة bye(), أي أننا نقول للبرنامج أنه بعد أن يتم تنفيذ الدالة hello(), استدعي الدالة bye()
مع ملاحظة عدم أهمية مكان الاعلان عن الدالة المؤجلة, فيمكننا مثلاً الاعلان عنها قبل الرسالة الترحيبية, وذلك لن يغير شيء بالبرنامج, مثلاً

func hello(name string){
	defer bye()
	fmt.Println("\nHello, ",name)
}

والان ننشئ الدالة bye()

func bye(){
	fmt.Println("\nBye, closing window in 5 seconds.")
	time.Sleep(5 * time.Second)
	os.Exit(3)
}

في السطر الأول من محتوى الدالة, نقوم بإظهار رسالة التوديع ونعلم المستخدم أن النافذة سيتم اغلاقها بعد 5 ثواني.
في السطر الثاني استخدمنا حزمة التوقيت time وبالتحديد الدالة Sleep منها, والتي تقوم بتجميد البرنامج لمدة زمنية من اختيارنا, وبعد انتهاء المدة ينتقل البرنامج لتنفيذ السطر التالي.
وفي السطر الثالث استخدمنا حزمة النظام os وبالتحديد الدالة Exit التي تأمر نظام التشغيل أن يقوم بإغلاق نافذة البرنامج, وبالنسبة للقيمة 3 التي تم تمريرها في الدالة فهذه تُدعى برمز الاغلاق exitCode وسنتكلم عنها لاحقاً.

والان دالة البرنامج الاساسية main, نستخدم الحزمة bufio لانشاء برنامج يستقبل مانكتبه من كلام (أي الاسم الذي يدخله المستخدم)
ومن ثم نقوم بتمرير هذا الاسم الى الدالة hello() وهي التي ستتكفل بعرض رسالة ترحيبية ومن ثم تقوم باستدعاء الدالة bye()

func main() {

  reader := bufio.NewReader(os.Stdin)

  for {
    fmt.Print("Enter your name: ")
    text, _ := reader.ReadString('\n')

    hello(text)

  }

}

ويكون شكل البرنامج النهائي كالاتي

package main

import (
  "bufio"
  "fmt"
  "os"
  "time"
)


func hello(name string){
	defer bye()
	fmt.Println("\nHello, ",name)
}


func bye(){
	fmt.Println("\nBye, closing window in 5 seconds.")
	time.Sleep(5 * time.Second)
	os.Exit(3)
}


func main() {

  reader := bufio.NewReader(os.Stdin)

  for {
    fmt.Print("Enter your name: ")
    text, _ := reader.ReadString('\n')

    hello(text)

  }

}

ومن ثم نقوم بتجميع البرنامج بواسطة الامر go build وتشغيله وستظهر النوافذ الاتية

عند بدء البرنامج

 

عند ادخال الاسم والضغط على Enter

وستنغلق النافذة بعد 5 ثواني.

ويمكن أيضاً استخدام defer مع الأساليب Methods

هل يمكن استخدام defer مع عدة دوال في برنامج واحد ؟
نعم, يمكن ذلك, وفي هذه الحالة يقوم البرنامج باستدعاء وتنفيذ الدوال المؤجلة عكسياً حسب مكان الاعلان عنها وذلك حسب نظام LIFO (Last in First Out)

مثال

package main

import (
	"fmt"
)

func show_number(number int) {
	fmt.Println(number)
}

func main() {
	var numbers = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}

	for _, v := range numbers {
		defer show_number(v)
	}
}

أنشئنا شريحة باسم numbers فيها الارقام من 1 الى 9, وقمنا بالتكرار على الشريحة بواسطة range ومن ثم استخدام الدالة المؤجلة defer لعرض كل رقم

ونلاحظ بنتيجة تنفيذ البرنامج أنه عرض الأرقام من الأخير الى الاول

9
8
7
6
5
4
3
2
1
ملاحظة: يمكنك تشغيل أكواد وأمثلة لغة غو من خلال GoLang Playground أو GoPlay.Space .

نبذة عن الكاتب

Firas M. Darwish

Software Engineer, PHP/Laravel, C#, GoLang, founder of ArGoLang.com & others ..

شاركنا رأيك :)