الأدوية العامة في Go: كيف يغير البرمجة العامة قواعد اللعبة

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

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

ابدأ الدورة

بدأ كل شيء مع Go 1.18: لماذا الأدوية العامة ليست مجرد ميزة عصرية؟

\n\n

لفترة طويلة، كان مجتمع Go يفتخر ببساطة اللغة. كان غياب البرمجة العامة (generics) يعتبر خيارًا واعيًا: "لسنا بحاجة إلى قوالب معقدة، نكتب كودًا مفهومًا". لكن الواقع فرض نفسه. لقد سئم المطورون من نسخ ولصق الدوال لأنواع int و string و float64 - أو استخدام interface{} مع تحويل الأنواع لاحقًا، مما يفقد الأمان في مرحلة التجميع.

\n\n

كان إصدار Go 1.18 (عام 2022) ثورة. أضافت الأدوية العامة (generics) إلى اللغة معاملات الأنواع (type parameters) و القيود (constraints). الآن يمكن لمبرمجي Go كتابة هياكل بيانات وخوارزميات عامة دون التضحية بالأداء والتصنيف الصارم.

\n\n

في هذه المقالة على pythonlib.ru، سنفهم كيف تعمل generics في Go، ونرى أمثلة حقيقية للكود، ونفهم متى يجب استخدامها ومتى لا. هيا بنا!

\n\n

ما هي الأدوية العامة في Go بكلمات بسيطة؟

\n\n

تخيل أنك تكتب دالة تجد العنصر الأدنى في شريحة. بدون الأدوية العامة، سيكون عليك إنشاء ثلاث نسخ: لـ int و float64 و string. أو استخدام interface{} مع تحويل الأنواع - بطيء وغير آمن.

\n\n

تسمح لك الأدوية العامة بكتابة دالة واحدة تعمل مع أي نوع يفي بشروط معينة. الصياغة بسيطة: بعد اسم الدالة، بين قوسين مربعين، تُحدد معاملات الأنواع.

\n\n

الصياغة: الأقواس المربعة وكلمة any

\n\n
package main\n\nimport "fmt"\n\n// Min — دالة عامة للبحث عن الحد الأدنى\nfunc Min[T any](a, b T) T {\n    // خطأ: العامل < غير معرّف لـ any\n    // if a < b {\n    //     return a\n    // }\n    return b\n}
\n\n

الكود أعلاه لن يتم تجميعه، لأن any هو واجهة فارغة (مرادف لـ interface{}). لا يعرف المترجم ما إذا كان النوع يدعم العامل <. يجب إضافة قيد (constraint).

\n\n

قيود الأنواع: constraints

\n\n

في Go، تُحدد القيود من خلال الواجهات. يمكن استخدام القيود المضمنة من حزمة golang.org/x/exp/constraints أو كتابة قيود خاصة بك.

\n\n
import (\n    "fmt"\n    "golang.org/x/exp/constraints"\n)\n\n// Min تعمل مع أي نوع مرتب\nfunc Min[T constraints.Ordered](a, b T) T {\n    if a < b {\n        return a\n    }\n    return b\n}\n\nfunc main() {\n    fmt.Println(Min(10, 20))       // 10\n    fmt.Println(Min(3.14, 2.71))   // 2.71\n    fmt.Println(Min("apple", "banana")) // "apple"\n}
\n\n

لاحظ: constraints.Ordered يشمل جميع الأنواع التي تم تعريف العوامل < و <= و > و >= لها - وهي int و float و string.

\n\n

أمثلة عملية: من البسيط إلى المعقد

\n\n

دعونا نرى كيف تبسط الأدوية العامة في Go كتابة الكود الحقيقي.

\n\n

1. مكدس عام (Stack)

\n\n

بدون الأدوية العامة، كان يجب تخزين []interface{} وإجراء type assertion. مع generics - أنيق وآمن.

\n\n
package main\n\nimport "fmt"\n\n// Stack — هيكل بيانات عام\ntype Stack[T any] struct {\n    items []T\n}\n\nfunc (s *Stack[T]) Push(item T) {\n    s.items = append(s.items, item)\n}\n\nfunc (s *Stack[T]) Pop() (T, bool) {\n    if len(s.items) == 0 {\n        var zero T\n        return zero, false\n    }\n    item := s.items[len(s.items)-1]\n    s.items = s.items[:len(s.items)-1]\n    return item, true\n}\n\nfunc main() {\n    intStack := Stack[int]{}\n    intStack.Push(1)\n    intStack.Push(2)\n    val, ok := intStack.Pop()\n    fmt.Println(val, ok) // 2 true\n\n    strStack := Stack[string]{}\n    strStack.Push("hello")\n                

المدونات

توصيات الكتب