تُعَدّ الدالة funtion كتلةً من التعليمات التي تنفِّذ إجراءً ما، ويمكن بعد تعريفها إعادة استخدامها في أكثر من موضع. تجعل الدوال الشيفرة تركيبية modular، مما يسمح بتقسيم الشيفرة إلى أجزاء صغيرة سهلة الفهم واستخدامها مرارًا وتكرارًا. تضم لغة جو مكتبةً قياسيةً تدعى fmt
، إذ تحتوي على عدد من الدوال المُضمّنة التي قد تكون شائعة بالنسبة لك مثل:
-
الدالة
()fmt.Println
تُستخدَم للطباعة على شاشة الخرج القياسية المُستخدَمة. -
الدالة
()fmt.Printf
تُستخدَم للطباعة مع إمكانية تنسيق الخرج.
تتضمن أسماء الدوال الأقواس وقد تتضمن معامِلات أيضًا، وسنتعلم في هذا المقال كيفية تعريف الدوال وكيفية استخدامها في البرامج.
تعريف الدالة
لنبدأ بتحويل برنامج "Hello, World!" إلى دالة، لذا أنشئ ملفًا نصيًا جديدًا وافتحه في محرر النصوص المفضل عندك ثم استدع البرنامج hello.go.
تُعرَّف الدالة باستخدام الكلمة المفتاحية func
متبوعة باسم من اختيارك ثم قوسين يمكن أن يَحتويا المعامِلات التي ستأخذها الدالة ثم ينتهي التعريف بنقطتين، وسنعرّف هنا دالةً باسم
hello():
func hello() {}
أعددنا في الشفرة أعلاه تعليمة التهيئة لإنشاء الدالة، وبعد ذلك سنضيف سطرًا ثانيًا مُزاحًا بأربع مسافات بيضاء ثم سنكتب التعليمات التي ستنفّذها الدالة، وفي هذه الحالة سنطبع العبارة !Hello, World
في الطرفية:
func hello() { fmt.Println("Hello, World!") }
أتممنا تعريف دالتنا ولكن إذا نَفَّذنا البرنامج الآن، فلن يحدث أيّ شيء لأننا لم نستدع الدالة، لذلك سنستدعي الدالة hello()
ضمن الدالة ()main
كما يلي:
package main import "fmt" func main() { hello() } func hello() { fmt.Println("Hello, World!") }
لننفّذ البرنامج الآن كما يلي:
$ go run hello.go
يجب أن تحصل على الخرج التالي:
Hello, World!
الدالة ()main
هي دالة خاصة تخبر المُصرّف أنّ هذا هو المكان الذي يجب أن يبدأ منه البرنامج، فأيّ برنامج تريده أن يكون قابلاً للتنفيذ (برنامج يمكن تشغيله من الطرفية)، فستحتاج إلى دالة ()main
، كما يجب أن تظهر الدالة ()main
مرةً واحدةً فقط وأن تكون في الحزمة main
ولا تستقبل أو تعيد أيّ وسائط، وهذا يسمح بتنفيذ البرنامج في أيّ برنامج جو آخر حسب المثال التالي:
package main import "fmt" func main() { fmt.Println("this is the main section of the program") }
بعض الدوال أكثر تعقيدًا بكثير من الدالة hello()
التي عرّفناها أعلاه، إذ يمكننا على سبيل المثال استخدام حلقة for
والتعليمات الشرطية وغيرها داخل كتلة الدالة، فالدالة المُعرّفة أدناه على سبيل المثال تستخدِم تعليمةً شرطيةً للتحقق مما إذا كانت المدخلات الممرّرة إلى المتغير name
تحتوي على حرف صوتي vowel، ثم تستخدِم الحلقة for
للتكرار على الحروف الموجودة في السلسلة النصية name
.
package main import ( "fmt" "strings" ) func main() { names() } func names() { fmt.Println("Enter your name:") var name string fmt.Scanln(&name) // Check whether name has a vowel for _, v := range strings.ToLower(name) { if v == 'a' || v == 'e' || v == 'i' || v == 'o' || v == 'u' { fmt.Println("Your name contains a vowel.") return } } fmt.Println("Your name does not contain a vowel.") }
تستخدِم الدالة names()
التي عرّفناها أعلاه تعليمةً شرطيةً وحلقة for
، وهذا توضيح لكيفية تنظيم الشيفرة البرمجية ضمن تعريف الدالة، كما يمكننا أيضًا جعل التعليمة الشرطية والحلقة for
دالتين منفصلتين. يجعل تعريف الدوال داخل البرامج الشفرة البرمجية تركيبيةً modular وقابلةً لإعادة الاستخدام، وذلك سيتيح لنا استدعاء الدالة نفسها دون إعادة كتابة شيفرتها في كل مرة.
المعاملات
عرّفنا حتى الآن دالة ذات قوسين فارغين لا تأخذ أيّ وسائط arguments، وسنتعلم في هذا القسم كيفية تعريف المعامِلات parameters وتمرير البيانات إلى الدوال.
يُعَدّ المعامِل كيانًا مُسمًّى يوضَع في تعريف الدالة ويعرِّف وسيطًا يمكن أن تقبله الدالة عند استدعائها، ويجب عليك في لغة Go أن تحدد نوع البيانات data type لكل معامِل
لننشئ برنامجًا يُكرر كلمة عدة مرات، إذ سنحتاج إلى متغير من النوع string
سنسميه word
ومتغير من النوع int
سنسميه reps
يُحدد عدد التكرارات.
package main import "fmt" func main() { repeat("Sammy", 5) } func repeat(word string, reps int) { for i := 0; i < reps; i++ { fmt.Print(word) } }
مرّرنا السلسلة Sammy
إلى المتغير word
والقيمة 5 إلى المعامِل reps
وذلك وفقًا لترتيب المعامِلات في ترويسة الدالة repeat
، إذ تتضمّن الدالة حلقة for
تطبع قيمة المعامِل word
عدة مرات يُحدّدها المعامِل reps
، وسيكون الخرج كما يلي:
SammySammySammySammySammy
إذا كانت لديك مجموعة من المعامِلات وجميعها تمتلك القيمة نفسها، فيمكنك تجاهل تحديد النوع من أجل كل متغير كما سنرى، لذا دعنا ننشئ برنامجًا صغيرًا يأخذ ثلاثة معامِلات x
و y
و z
من النوع int
، إذ سننشئ دالةً تجمع تلك المعامِلات وفق عدة مجموعات ثم تطبع الدالة حاصل جمعها.
package main import "fmt" func main() { addNumbers(1, 2, 3) } func addNumbers(x, y, z int) { a := x + y b := x + z c := y + z fmt.Println(a, b, c) }
عند تعريف الدالة addNumbers
لم نكن بحاجة إلى تحديد نوع كل متغير على حدة، وإنما وضعنا نوع بيانات كل المتغيرات مرةً واحدةً فقط.
مرّرنا العدد 1 إلى المعامل x
والعدد 2 إلى المعامل y
والعدد 3 إلى المعامل z
، إذ تتوافق هذه القيم مع المعامِلات المقابلة لها في ترتيب الظهور، ويُجري البرنامج العمليات الحسابية على المعامِلات على النحو التالي:
a = 1 + 2 b = 1 + 3 c = 2 + 3
تطبع الدالة أيضًا a
و b
و
c، وبناءً على العمليات الحسابية أعلاه، فستساوي قيمة a
العدد 3 و b
العدد 4 و c
العدد 5، ولننفّذ البرنامج سنكتب ما يلي:
$ go run add_numbers.go
سيكون الخرج كما يلي:
3 4 5
عندما نمرر 1 و 2 و 3 على أساس معامِلات إلى الدالة ()addNumbers
، فإننا نتلقى الناتج المتوقع.
تُعَدّ المعامِلات وسائط تُعرَّف عادة على أساس متغيرات ضمن تعريف الدالة، كما يمكن تعيين قيم إليها عند تنفيذ التابع بتمرير وسائط إلى الدالة.
إعادة قيمة
يمكن تمرير قيم إلى الدالة ويمكن كذلك أن تُنتج الدالة قيمةً وتُعيدها لمن استدعاها، إذ يمكن أن تنتج الدالة قيمةً عبر استخدام التعليمة return
وهي تعليمة اختيارية، ولكن في حال استخدامها ستُنهي الدالة عملها مباشرةً وتوقف تنفيذها وتُمرَّر قيمة التعبير الذي يعقُبها اختياريًا إلى المستدعي، كما يجب تحديد نوع البيانات المُعادة أيضًا.
استخدمنا حتى الآن الدالة ()fmt.Println
بدلاً من التعليمة return
في دوالنا لطباعة شيء بدلًا من إعادته، فلننشئ برنامجًا يعيد متغيرًا بدلًا من طباعته مباشرةً، لذا سننشئ برنامجًا في ملف نصي جديد يسمى double.go يحسب ناتج مُضاعفة المعامِل x
ويُسند الناتج إلى المتغير y
ثم يعيده، كما سنطبع المتغير result
والذي يساوي ناتج تنفيذ الدالة double(3)
.
package main import "fmt" func main() { result := double(3) fmt.Println(result) } func double(x int) int { y := x * 2 return y }
لننفّذ البرنامج كما يلي:
$ go run double.go
سيكون الخرج كما يلي:
6
خرج البرنامج هو العدد الصحيح 6 الذي أعادته الدالة وهو ما نتوقعه إذا طلبنا من جو حساب ناتج ضرب 2 بالعدد 3.
إذا حددنا نوع القيمة المُعادة فيجب علينا إعادة قيمة من هذا النوع وإلا فسيُعطي البرنامج خطأً في التصريف، ففي المثال التالي سنلغي تعليمة الإعادة المُستخدَمة في الشيفرة السابقة بوضع تعليق على تعليمة الإعادة لكي يتجاهلها المُصرّف كما يلي:
package main import "fmt" func main() { result := double(3) fmt.Println(result) } func double(x int) int { y := x * 2 // return y }
لنحاول تنفيذ البرنامج:
$ go run double.go
سيُشير الخرج إلى خطأ لأنه لم يجد تعليمة الإعادة return
:
./double.go:13:1: missing return at end of function
لا يمكن تصريف البرنامج بدون تعليمة الإعادة هذه، فعندما تصل الدالة إلى تعليمة return
فإنها ستُنهي تنفيذ الدالة حتى إذا كان هناك تعليمات تالية ضمنها:
package main import "fmt" func main() { loopFive() } func loopFive() { for i := 0; i < 25; i++ { fmt.Print(i) if i == 5 { //i == 5 أوقف الدالة عندما return } } fmt.Println("This line will not execute.") // هذا السطر لن ينفَّذ }
نستخدِم هنا حلقة for
تُؤدي عملية تكرار 25 مرة وبداخلها تعليمة if
تتحقق مما إذا كانت قيمة i
تساوي العدد 5، فإذا كانت كذلك، فسيكون لدينا تعليمة return
تُنهي تنفيذ الحلقة وتُنهي تنفيذ الدالة أيضًا، وهذا يعني أنّ باقي التكرارات لن تُنفّذ والسطر الأخير من الدالة This line will not execute
لن يُنفّذ.
يؤدي استخدام التعليمة return
داخل الحلقة for
إلى إنهاء الدالة، وبالتالي لن يُنفَّذ السطر الموجود خارج الحلقة، فإذا استخدمنا بدلًا من ذلك التعليمة break
، فسيُنفّذ السطر fmt.Println()
الأخير من المثال السابق.
نعيد التذكير أنَّ التعليمة return
تنهي عمل الدالة وقد تعيد قيمةً إذا أعقبها تعبير وكان ذلك محدد في تعريف الدالة.
إعادة عدة قيم
يمكن للدوال أن تُعيد أكثر من قيمة، إذ سنجعل برنامج repeat.go يُعيد قيمتين بحيث تكون القيمة الأولى القيمة المُكررة والثانية خطأً في حال كانت قيمة المعامِل reps
أصغر أو تساوي 0.
package main import "fmt" func main() { val, err := repeat("Sammy", -1) if err != nil { fmt.Println(err) return } fmt.Println(val) } func repeat(word string, reps int) (string, error) { if reps <= 0 { return "", fmt.Errorf("invalid value of %d provided for reps. value must be greater than 0.", reps) } var value string for i := 0; i < reps; i++ { value = value + word } return value, nil }
تتحقق الدالة repeat
بدايةً من أن الوسيط reps
صالح، فأيّ قيمة أقل أو تساوي الصفر ستؤدي إلى خطأ. بما أننا مررنا القيمة 1- إلى reps
فهذا سيؤدي إلى تحقق شرط حدوث خطأ، وبالتالي ستُعاد قيمتين الأولى هي سلسلة فارغة "" والثانية هي رسالة خطأ، وبالطبع يجب علينا إعادة قيمتين دومًا تبعًا للتعريف الذي وضعناه في ترويسة الدالة، إذ حددنا أنّ هناك قيمتان مُعادتان من الدالة؛ فالأولى هي سلسلة والثانية هي خطأ، ولهذا السبب أعدنا سلسلةً فارغةً في حال ظهور خطأ.
نستدعي الدالة repeat
بداخل الدالة main
ونُسند القيم المُعادة إلى متغيرين هما value
و err
، وبما أنّ هناك احتمال لحدوث خطأ، فسنتحقق في الأسطر التالية من وجوده، وفي حال وجوده سنطبع رسالةً تشير إلى الخطأ وسنستخدِم التعليمة return
للخروج من الدالة main
والبرنامج، وبتنفيذ البرنامج سنحصل على ما يلي:
invalid value of -1 provided for reps. value must be greater than 0.
ملاحظة: من السلوكيات الجيدة في البرمجة إعادة قيمتان أو ثلاثة، بالإضافة إلى إعادة كل الأخطاء كآخر قيمة معادة من الدالة. تعلّمنا في هذا القسم كيف نجعل تعليمة return
تُعيد أكثر من قيمة.
الدوال المرنة Variadic
الدالة المرنة Variadic هي دالة لا تقبل أي قيمة أو تقبل قيمةً واحدةً أو قيمتين أو أكثر على أساس وسيط واحد، والدوال المرنة ليست شائعة الاستخدام لكنها تجعل الشيفرة أنظف وأكثر قابليةً للقراءة، وأحد الأمثلة على هذا النوع من الدوال هو الدالة Println
من الحزمة fmt
:
func Println(a ...interface{}) (n int, err error)
نسمي الدالة التي تتضمن مُعامِلًا مُلحقًا بثلاثة نقاط ...
كما في الشيفرة أعلاه بالدالة المرنة، إذ تشير النقاط الثلاث إلى أنّ هذا المعامِل يمكن أن يكون صفر قيمة أو قيمةً واحدةً أو قيمتين أو عدة قيم، وبالتالي تُعَدّ الدالة fmt.Println
دالةً مرنةً لأنها تتضمن مُعامِلًا مرنًا يسمى a
.
سنستخدِم في المثال التالي الدالة المرنة السابقة وسنبيّن كيف أنه من الممكن أن نمرر لها عددًا غير مُحدد من الوسائط:
package main import "fmt" func main() { fmt.Println() fmt.Println("one") fmt.Println("one", "two") fmt.Println("one", "two", "three") }
كما تُلاحظ فإننا نستدعيها أول مرة بدون تمرير أيّ وسيط ثم نستدعيها مع تمرير وسيط واحد هو السلسلة one
ثم نستدعيها مع وسيطين ثم نستدعيها مع ثلاثة وسائط، ولننفذ البرنامج الآن:
$ go run print.go
سيكون الخرج كما يلي:
one one two one two three
لاحظ أنّ السطر الأول من الخرج فارغ لأننا استدعينا تعليمة الطباعة بدون تمرير أيّ متغير ثم السطر الثاني يحتوي على one
لأن دالة الطباعة التي استدعيناها في المرة الثانية تتضمنها، ثم one two
لأننا مررناهما إلى دالة الطباعة في المرة الثالثة، وأخيرًا السطر الأخير one two three
لأننا مررنا هذه الكلمات إلى دالة الطباعة في الشيفرة السابقة.
سنتحدّث الآن عن كيفية تعريف هذه الدوال بعد أن اطلعنا على كيفية استخدام الدوال المرنة.
تعريف الدوال المرنة
كما ذكرنا سابقًا فإن الدوال المرنة تُعرّف من خلال وضع ثلاث نقاط ...
بعد اسم أحد المعامِلات فيها، وفي المثال التالي سنعرّف دالةً نمرر لها أسماءً لكي تُحَييهم:
package main import "fmt" func main() { sayHello() sayHello("Sammy") sayHello("Sammy", "Jessica", "Drew", "Jamie") } func sayHello(names ...string) { for _, n := range names { fmt.Printf("Hello %s\n", n) } }
تتضمّن الدالة sayHello
معامِلًا اسمه names
من النوع string
، وكما نلاحظ فإنه توجد ثلاث نقاط بعد اسمه، وبالتالي هو معامل مرن أي يقبل عدد غير مُحدد من الوسائط، وبالتالي تُعَدّ الدالة sayHello
هي دالةً مرنةً.
تُعامِل هذه الدالة المعامِل names
على أنه شريحة من الأسماء، أي أنها تعامله على أساس شريحة من السلاسل النصية string[]
، وبالتالي يمكننا التكرار عليه بحلقة for
من خلال استخدام العامِل range
.
ستحصل عند تنفيذ هذه الشيفرة على ما يلي:
Hello Sammy Hello Sammy Hello Jessica Hello Drew Hello Jamie
لاحظ أنه في المرة الأولى التي استدعينا فيها الدالة sayHello
لم يُطبع أيّ شيء، وذلك لأننا لم نمرر لها أيّ قيمة، أي عمليًّا هي شريحة فارغة، وبالتالي لا تتضمن أي قيمة ليُكرر عليها، والآن سنُعدّل الشيفرة السابقة بحيث تطبع عبارةً مُحددةً عندما لا تُمرّر أيّ قيمة:
package main import "fmt" func main() { sayHello() sayHello("Sammy") sayHello("Sammy", "Jessica", "Drew", "Jamie") } func sayHello(names ...string) { if len(names) == 0 { fmt.Println("nobody to greet") return } for _, n := range names { fmt.Printf("Hello %s\n", n) } }
أضفنا تعليمة if
تتحقق مما إذا كانت الشريحة فارغةً وهذا يُكافئ أن يكون طولها 0، وفي هذه الحالة سنطبع nobody to greet
:
nobody to greet Hello Sammy Hello Sammy Hello Jessica Hello Drew Hello Jamie
يجعل استخدام الدوال والمتغيرات المرنة شيفرتك أكثر قابليةً للقراءة، وسنُنشئ الآن دالةً مرنةً تربط الكلمات اعتمادًا على رمز مُحدّد، لكن سنكتب أولًا دالةً ليست مرنة لنُبيّن الفرق:
package main import "fmt" func main() { var line string line = join(",", []string{"Sammy", "Jessica", "Drew", "Jamie"}) fmt.Println(line) line = join(",", []string{"Sammy", "Jessica"}) fmt.Println(line) line = join(",", []string{"Sammy"}) fmt.Println(line) } func join(del string, values []string) string { var line string for i, v := range values { line = line + v if i != len(values)-1 { line = line + del } } return line }
مرّرنا هنا الفاصلة ,
إلى الدالة join
لكي يُنجز الربط اعتمادًا عليها، ثم مرّرنا شريحةً من الكلمات لكي تُربط، فكان الخرج كما يلي:
Sammy,Jessica,Drew,Jamie Sammy,Jessica Sammy
لاحظ هنا أنّ تعريف شريحة في كل مرة نستدعي فيها هذه الدالة قد يكون مُملًا وأكثر صعوبةً في القراءة، لذا سنُعرّف الآن الشيفرة نفسها لكن مع دالة مرنة:
package main import "fmt" func main() { var line string line = join(",", "Sammy", "Jessica", "Drew", "Jamie") fmt.Println(line) line = join(",", "Sammy", "Jessica") fmt.Println(line) line = join(",", "Sammy") fmt.Println(line) } func join(del string, values ...string) string { var line string for i, v := range values { line = line + v if i != len(values)-1 { line = line + del } } return line }
سنحصل عند تشغيل البرنامج على خرج المثال السابق نفسه:
Sammy,Jessica,Drew,Jamie Sammy,Jessica Sammy
يمكن بسهولة ملاحظة أنّ استخدام مفهوم الدالة المرنة قد جعل من الدالة join
أكثر قابليةً للقراءة.
ترتيب الوسائط المرنة
يمكنك تعريف معامِل مرن واحدة فقط في الدالة ويجب أن يكون هو المعامِل الأخير في ترويسة الدالة، فإذا عرّفتَ أكثر من معامِل مرن أو وضعته قبل المعامِلات العادية، فسيظهر لك خطأ وقت التصريف compilation error.
package main import "fmt" func main() { var line string line = join(",", "Sammy", "Jessica", "Drew", "Jamie") fmt.Println(line) line = join(",", "Sammy", "Jessica") fmt.Println(line) line = join(",", "Sammy") fmt.Println(line) } func join(values ...string, del string) string { var line string for i, v := range values { line = line + v if i != len(values)-1 { line = line + del } } return line }
وضعنا هنا المعامِل المرن values
أولًا ثم وضعنا المعامِل العادي del
، وبالتالي خالفنا الشرط المذكور سلفًا، وبالتالي سنحصل على الخطأ التالي:
./join_error.go:18:11: syntax error: cannot use ... with non-final parameter values
عند تعريف دالة مرنة لا يمكن أن يكون المعامِل الأخير إلا معاملًا مرنًا.
تفكيك الوسائط
رأينا كيف أنّ المعامل المرن سيسمح لنا بتمرير 0 قيمة أو قيمة واحدة أو أكثر من قيمة إلى الدالة، لكن هناك حالات سيكون لدينا فيها شريحة من القيم نريد تمريرها إلى الدالة المرنة، لذا دعونا نرى الدالة join
التي بنيناها مؤخرًا لرؤية ما يحدث:
package main import "fmt" func main() { var line string names := []string{"Sammy", "Jessica", "Drew", "Jamie"} line = join(",", names) fmt.Println(line) } func join(del string, values ...string) string { var line string for i, v := range values { line = line + v if i != len(values)-1 { line = line + del } } return line }
سنحصل عند تشغيل البرنامج على خطأ وقت التصريف:
./join-error.go:10:14: cannot use names (type []string) as type string in argument to join
على الرغم من أن الدالة المرنة ستحوّل المعامِل values ...string
إلى شريحة من السلاسل النصية string[]
، إلا أنّ هذا لا يعني أنه بإمكاننا تمرير شريحة من السلاسل على أساس وسيط، فالمُصرّف يتوقع وسائط منفصلةً من نوع سلسلة نصية.
يمكننا لحل هذه المشكلة تفكيك قيم الشريحة -أي فصلها عمليًّا- من خلال وضع ثلاثة نقط بعد اسم الشريحة عندما نُمررها لدالة مرنة.
package main import "fmt" func main() { var line string names := []string{"Sammy", "Jessica", "Drew", "Jamie"} line = join(",", names...) fmt.Println(line) } func join(del string, values ...string) string { var line string for i, v := range values { line = line + v if i != len(values)-1 { line = line + del } } return line }
لاحظ أننا وضعنا 3 نقاط بعد اسم الشريحة names
عندما مررناها إلى الدالة join
، وهذا يؤدي إلى تفكيك عناصر الشريحة، وبالتالي كأنها قيم منفصلة، وسيكون الخرج كما يلي:
Sammy,Jessica,Drew,Jamie
لاحظ أنه مازال بإمكاننا عدم تمرير أيّ شيء أو تمرير أيّ عدد نريده من القيم، ويبيّن المثال التالي كل الحالات:
package main import "fmt" func main() { var line string line = join(",", []string{"Sammy", "Jessica", "Drew", "Jamie"}...) fmt.Println(line) line = join(",", "Sammy", "Jessica", "Drew", "Jamie") fmt.Println(line) line = join(",", "Sammy", "Jessica") fmt.Println(line) line = join(",", "Sammy") fmt.Println(line) } func join(del string, values ...string) string { var line string for i, v := range values { line = line + v if i != len(values)-1 { line = line + del } } return line }
سيكون الخرج كما يلي:
Sammy,Jessica,Drew,Jamie Sammy,Jessica,Drew,Jamie Sammy,Jessica Sammy
أصبحنا الآن نعرف كيف نمرِّر 0 قيمة أو أكثر إلى دالة مرنة، كما أصبحنا نعرف كيف يمكننا تمرير شريحة إلى دالة مرنة.
غالبًا ما تكون الدوال المرنة مفيدةً في الحالات التالية:
- عندما تكون بحاجة إلى تعريف شريحة مؤقتًا من أجل تمريرها إلى دالة.
- لجعل الشيفرة أكثر قابليةً للقراءة.
- عندما يكون عدد الوسائط غير معروف أو متغير مثل دالة الطباعة.
الخاتمة
تُعَدّ الدوال كتلًا من التعليمات البرمجية التي تُنفِّذ إجراءات معيّنة داخل البرنامج، كما تساعد على جعل الشفرة تركيبيةً وقابلةً لإعادة الاستخدام، بالإضافة إلى أنها تنظمها وتسهل من قراءتها، كما تجعل الدوال المرنة الشيفرة أكثر قابليةً للقراءة، إلا أنها ليست شائعة الاستخدام، ولتتعلم كيف تجعل برنامجك تركيبيًّا أكثر، فيمكنك قراءة مقال كيفية تعريف الحزم في لغة جو Go.
ترجمة -وبتصرف- للمقالَين How To Define and Call Functions in Go وللمقال How To Use Variadic Functions in Go لصاحبه Gopher Guides.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.