لغة البرمجة GO الجزء الخامس – التوابع

التوابع أو الدوال البرمجية هي من العناصر الأساسية في جميع لغات البرمجة. وفي هذا الجزء سوف نتعرف على كيفية كتابة واستخدام التوابع في لغة البرمجة GO.

يمكن تعريف التابع أنه عبارة عن مجموعة من الأوامر البرمجية, نقوم بكتابتها في مكان واحد هو التابع. ومن ثم نستدعي هذا التابع ليتم تنفيذ هذه الأوامر دفعة واحدة في أي مكان أو أي وقت نريده ضمن البرنامج.

وطريقة تعريف التابع بسيطة ويمكن توضيحها كالتالي:

func FunctionName(param1 type, param2 type) type {

  // الأوامر التي نريد تنفيذها

  return result
}

حيث نكتب الكلمة func والتي تعني بداية تعريف تابع. ثم نكتب اسم التابع .
ونختار الإسم بحيث لا يحتوي فراغات أو احرف غريبة ولا يبدأ برقم.

ثم بعد الإسم نضع بين قوسين جميع المعاملات التي نريدها أن تكون دخلاً لهذا التابع.
بحيث نكتب إسم المعامل ومن ثم نوعه. ونفصل بين المعاملات بفواصل .
على سبيل المثال المعامل الأول هنا اسمه param1 والمعامل الثاني param2

ثم بعد الأقواس المغلقة نكتب نوع البيانات التي سوف يعيدها التابع بعد انتهاء تنفيذه.
وطبعا هذا النوع يمكن أن يكون رقم أو نص أو أي نوع من البيانات.

ثم بعدها نكتب بين الأقواس المنحنية {} جميع الأوامر التي نريد تنفيذها عند استدعاء التابع.

ملاحظة: في لغة البرمجة GO يجب أن يكون القوس المنحني الأول في نفس السطر الذي نكتب فيه اسم التابع. وغير ذلك نجد خطأ خلال تنفيذ البرنامج.

وفي النهاية عندما نريد الخروج من التابع نستخدم تعليمة return ونكتب بعدها القيمة التي نريدها لتكون خرج التابع.

المثال التالي لتابع بسيط يقوم بجمع عددين ويعيد نتيجة الجمع في خرجه.

func sum(x int, y int) int {

	var z = x + y

	return z
}

هذا التابع إسمه sum , وله في الدخل معاملين , الأول x من نوع int , والثاني y من نوع int

والنتيجة التي يعيدها التابع هي من نوع int أيضاً

أما التعليمات التي يقوم بتنفيذها التابع فهي تعريف متحول إسمه z . وقيمة هذا المتحول هي مجموع المعاملات أو متحولات الدخل x و y

وفي النهاية تعليمة return التي تعني الخروج من التابع مع إعادة قيمة المتحول z في خرج التابع.

لنقوم باستخدام هذا التابع في برنامج كامل ونرى النتيجة:

package main

import ("fmt")

func sum(x int, y int) int {

	var z = x + y

	return z
}

func main() {

  var aa = sum(5, 4)

  fmt.Println("a = ", aa)

}

بتنفيذ هذا البرنامج نرى النتيجة هي طباعة : a = 9

والآن لنكتب تابع آخر يقوم بالتحقق من أن القيمة في دخله أكبر من الصفر أم لا.
بحيث تكون نتيجة المقارنة هي true اذا كانت أكبر من الصفر . وغير ذلك تكون false

func isMoreThanZero(x int) bool {
	if(x > 0){
		return true
	}

	return false
}

func main() {
  var i = isMoreThanZero(5)
  var j = isMoreThanZero(-2)

  fmt.Println("i is ", i)
  fmt.Println("j is ", j)

}

في هذا المثال التابع isMoreThanZero له دخل واحد وهو x من نوع عدد صحيح
والقيمة التي يعيدها التابع في خرجه هي من نوع bool

أما تعليمات التابع فهي عملية تحقق باستخدام التعليمة if . التي تتحقق من أن قيمة x أكبر من الصفر.
فإذا كانت نتيجة الشرط محققة عندها يتم تنفيذ تعليمة return التابعة للشرط if

وفي حال عدم تحقق الشرط ينتقل التنفيذ إلى تعليمة return الثانية التي تعيد القيمة false

لنقوم بتنفيذ البرنامج ونرى النتيجة:

i is  true
j is  false

يوجد ميزة جديدة في لغة البرمجة GO وهي إمكانية أن يعيد التابع أكثر من قيمة .
حيث جرت العادة في باقي لغات البرمجة أن يرجع التابع بعد تنفيذه قيمة معينة من نوع محدد مسبقا. كما شاهدنا في المثال السابق. حيث التابع يعيد قيمة من نوع bool

ولجعل التابع يعيد أكثر من قيمة. أي مصفوفة من البيانات أو المتحولات. نستخدم الطريقة التالية لتعريف التابع :

func test(x int) (k int, str string) {
	
	if(x == 0){
		str = "X was == 0"
	}else {		
		str = "X was != 0"
	}

	k = x + 1

	return
}

func main() {

	var i, j = test(5)

  fmt.Println(i)
  fmt.Println(j)

}

في السطر الأول من تعريف التابع test كتبنا بين قوسين المتحول x على أنه دخل للتابع.
أما بعدها كتبنا بين قوسين جديدين في نفس السطر مجموعة من المتحولات هي k من نوع عدد صحيح. والمتغير str من نوع string . وهذه المتحولات هي القيم التي سوف يعيدها التابع بعد تنفيذه.

وهذه المتغيرات يتم إرجاعها على شكل مصفوفة. العنصر الأول فيها هو المتحول الأول k . والثاني هو المتحول str . وهكذا .

حيث ما يقوم به التابع هو عملية التحقق عبر الشرط if من أن القيمة x تساوي الصفر.
فإذا كانت محققة نضع في المتحول str ما يدل على ذلك من نص.
أما إذا لم يتحقق ينتقل التنفيذ إلى القسم else ونضع قيمة مختلفة في المتحول str

وبعدها نضع في المتحول k قيمة المتحول x مضافاً إليها واحد.

ثم تعليمة return التي تعني الخروج من التابع و إرجاع القيم التي عرفناها قبل قليل على شكل مصفوفة.

هذا كل شيء بالنسبة للتابع test

أما في التابع main نلاحظ أننا عرفنا متحولين في نفس السطر وهما i و j
ووضعنا فيهما نتيجة تنفيذ التابع test . والتي كما قلنا هي عبارة عن مصفوفة. بحيث توضع القيمة الأولى في المتحول i والقيمة الثانية في المتحول j

ثم قمنا بطباعة قيمة كل من هذين المتحولين . والنتيجة هي:

6
X was != 0
العودية

كما هو الحال في باقي لغات البرمجة, فإن العودية ممكنة في لغة البرمجة GO.
والمقصود بالعودية هو إمكانية التابع أن يستدعي نفسه.

لنأخذ المثال التالي لتوضيح فكرة العودية:

func countDown(x int){

	fmt.Println(x)

	if(x > 0){
		x = x - 1
		countDown(x)
	}
}

func main() {

	countDown(5)

}

التابع countDown قمنا بكتابته بحيث له دخل واحد هو المتحول x , ولا يعيد أي قيمة في خرجه.

عند تنفيذ هذا التابع في البداية يتم طباعة قيمة x
ثم يتم التحقق من أن قيمة x أكبر من الصفر, فإذا تحقق الشرط يتم إنقاص قيمة x بمقدار واحد.
ثم نعيد استدعاء التابع مرة إخرى. ولكن بقيمة دخل جديدة هي x مطروح منها واحد.

وتستمر هذه العملية بالتكرار حتى تصبح قيمة x تساوي الصفر وينتهي تنفيذ التابع.
والنتيجة في كل مرة يتم استدعاء التابع يطبع على الشاشة قيمة x كما في الشكل :

5
4
3
2
1
0

هذا مفهوم العودية ببساطة. ويمكن الاستفادة من هذه الخاصية لإجراء عمليات أكثر تعقيدا حسب الحاجة.

الدوال من النوع Closure

الدوال Closures هي توابع يتم تعريفها ضمن تابع آخر يكون بمثابة التابع الأب لها. وهنا تكون جميع المتحولات في التابع الأب مرئية بالنسبة للتابع Closure .
وعادة يتم تعريفها كمالو أنها قيمة توضع في متحول. كما في الشكل التالي:

func main(){
    x := 1
    inc := func() int {
        x++
        return x
    }
    fmt.Println(inc())
    fmt.Println(inc())
    fmt.Println(inc())
}

هنا لدينا التابع الأب هو main . ويوجد في بدايته تعريف للمتحول x ذو قيمة الافتراضية تساوي 1

ثم قمنا بتعريف دالة أو تابع Closure يقوم بزيادة قيمة المتحول x ثم يعيد القيمة الجديدة بعد الزيادة .
ونضع هذه الدالة في متحول اسمه inc

ثم بعدها نقوم باستدعاء هذا التابع وطباعة نتيجة تنفيذه في كل مرة.
ونتيجة تنفيذ البرنامج هي طباعة مايلي على الشاشة:

2
3
4

من المثال واضح لنا أن أهم ميزة لهذا النوع من التوابع أنه يستطيع التعامل مع متحولات التابع الأب.
وهذا يفيد في استخدام فوائد الدوال مثل تكرار العمليات بدون اعادة كتابة التعليمات بشكل متكرر . مع المحافظة على بساطة كتابة الأوامر دون الحاجة لتمرير الكثير من المعاملات بين التوابع .