البرمجة الوظيفية في Go: المبادئ والأمثلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

البرمجة الوظيفية في Go: من الأمرية إلى التصريحية



ترتبط لغة Go (Golang) تقليديًا بالبرمجة الأمرية والمتزامنة، ومع ذلك فإن نظام الأنواع القوي فيها ودعمها للدوال من الدرجة الأولى يجعل من الممكن تطبيق العديد من مبادئ البرمجة الوظيفية (FP). في هذه المقالة، سندرس كيفية تطبيق أساليب البرمجة الوظيفية في Go دون التضحية بالأداء وقابلية قراءة الكود.



المبادئ الأساسية للبرمجة الوظيفية في سياق Go



البرمجة الوظيفية في Go لا تعني الرفض الكامل للحالة القابلة للتغيير. بدلاً من ذلك، نستخدم المفاهيم التالية:



  • الدوال الخالصة — الدوال التي تعتمد نتيجتها فقط على الوسائط، دون تأثيرات جانبية.
  • عدم التغيير — تفضيل إنشاء هياكل بيانات جديدة بدلاً من تعديل الموجودة.
  • الدوال عالية المستوى — الدوال التي تأخذ دوال أخرى كوسائط أو تُرجعها.
  • الإغلاقات — الدوال التي تلتقط متغيرات من النطاق الخارجي.


الدوال عالية المستوى: map، filter، reduce



لا تحتوي Go على أدوية عامة مدمجة (حتى الإصدار 1.18)، لذلك يتم تنفيذ map و filter و reduce الكلاسيكية عبر الواجهات أو النسخ الصريح. دعنا نلقي نظرة على مثال مع الأعداد الصحيحة:



package main

import "fmt"

// Map — تطبق دالة على كل عنصر من شريحةfunc Map(s []int, fn func(int) int) []int { result := make([]int, len(s)) for i, v := range s { result[i] = fn(v) } return result}

// Filter — تحتفظ فقط بالعناصر التي تحقق الشرطfunc Filter(s []int, fn func(int) bool) []int { var result []int for _, v := range s { if fn(v) { result = append(result, v) } } return result}

// Reduce — تدمج شريحة في قيمة واحدةfunc Reduce(s []int, init int, fn func(int, int) int) int { acc := init for _, v := range s { acc = fn(acc, v) } return acc}

func main() { nums := []int{1, 2, 3, 4, 5}

// مضاعفة كل عنصر doubled := Map(nums, func(x int) int { return x * 2 }) fmt.Println("Map:", doubled) // [2 4 6 8 10]

// الاحتفاظ فقط بالأعداد الزوجية evens := Filter(nums, func(x int) bool { return x%2 == 0 }) fmt.Println("Filter:", evens) // [2 4]

// جمع كل العناصر sum := Reduce(nums, 0, func(acc, x int) int { return acc + x }) fmt.Println("Reduce:", sum) // 15}


مهم: في Go 1.18+ مع الأدوية العامة، يمكنك إنشاء إصدارات عالمية:



// Generic Mapfunc MapGeneric[T, U any](s []T, fn func(T) U) []U {    result := make([]U, len(s))    for i, v := range s {        result[i] = fn(v)    }    return result}


الإغلاقات والكارينج في Go



الإغلاقات في Go هي أداة قوية لإنشاء دوال تحتفظ بالحالة. دعنا نلقي نظرة على مثال لمولد تسلسل:



package main

import "fmt"

// مولد تسلسل فيبوناتشيfunc fibonacci() func() int { a, b := 0, 1 return func() int { a, b = b, a+b return a }}

// الكارينج: دالة تأخذ الوسائط على مراحلفunc add(a int) func(int) int { return func(b int) int { return a + b }}

func main() { fib := fibonacci() fmt.Println(fib()) // 1 fmt.Println(fib()) // 1 fmt.Println(fib()) // 2

// الكارينج add5 := add(5) fmt.Println(add5(10)) // 15 fmt.Println(add5(20)) // 25}


الإغلاقات مفيدة بشكل خاص من أجل:

  • إنشاء دوال قابلة للتكوين (الوسيط)
  • تنفيذ نمط "مصنع الدوال"
  • تنظيم آليات الاستدعاء الرجعي


عدم التغي

المدونات

توصيات الكتب