الأصناف العامة (Generics) والكتابة في Swift: كيفية كتابة كود يعمل نيابة عنك

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

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

ابدأ الدورة

لماذا بدون الأصناف العامة (Generics) سيتحول كود Swift الخاص بك قريبًا إلى معكرونة (سباغيتي)

\n\n

تخيل أنك تكتب تطبيقًا لتوصيل البيتزا. تحتاج إلى معالجة الطلبات والعملاء والسعاة - وفي كل مرة تكتب نفس الكود للفرز أو البحث أو التصفية، مع تغيير نوع البيانات فقط؟ يبدو وكأنه كابوس لأي مطور. هنا يأتي دور الأصناف العامة (Generics) في Swift - أداة قوية تسمح لك بكتابة كود مرن وقابل لإعادة الاستخدام، دون التضحية بسلامة الأنواع.

\n\n

في هذه المقالة، لن نمر فقط على بناء الجملة. سنشرح كيف تعمل الكتابة في Swift والأصناف العامة معًا، لجعل كودك ليس فقط جميلاً بل وموثوقًا أيضًا. ستتعلم كيف تتخلص من النسخ واللصق، وكيف تستخدم protocol مع associatedtype، ولماذا جمل where هي أفضل صديق لك.

\n\n

ما هي الأصناف العامة (Generics) ولماذا تغير قواعد اللعبة

\n\n

الأصناف العامة (Generics، الأنواع العامة) هي آلية تسمح بكتابة دوال وهياكل وفئات وتعدادات تعمل مع أي نوع بيانات يحقق شروطًا معينة. بدلاً من كتابة ثلاث نسخ من الدالة لـ Int و String و Double، تكتب نسخة واحدة تعمل مع أي نوع.

\n\n

في Swift، الكتابة صارمة وثابتة. هذا يعني أن المترجم يتحقق من الأنواع في مرحلة التجميع. الأصناف العامة لا تخالف هذه القاعدة - بل تجعلها أكثر مرونة. المترجم يستنتج النوع المحدد عند استدعاء الدالة، لكن التحقق يبقى قائمًا.

\n\n

المثال الأول: دالة بدون أصناف عامة

\n\n
// سيء: ثلاث دوال لثلاثة أنواع\nfunc swapInts(_ a: inout Int, _ b: inout Int) {\n    let temp = a\n    a = b\n    b = temp\n}\n\nfunc swapStrings(_ a: inout String, _ b: inout String) {\n    let temp = a\n    a = b\n    b = temp\n}\n\nfunc swapDoubles(_ a: inout Double, _ b: inout Double) {\n    let temp = a\n    a = b\n    b = temp\n}
\n\n

والآن - الحل الأنيق باستخدام الأصناف العامة:

\n\n
// جيد: دالة واحدة لجميع الأنواع\nfunc swapValues<T>(_ a: inout T, _ b: inout T) {\n    let temp = a\n    a = b\n    b = temp\n}\n\n// الاستخدام:\nvar x = 10\nvar y = 20\nswapValues(&x, &y) // T = Int\n\nvar name1 = "Alice"\nvar name2 = "Bob"\nswapValues(&name1, &name2) // T = String
\n\n

هل ترى السحر؟ <T> هو عنصر نائب (placeholder) للنوع. المترجم يقوم بتعويض النوع الحقيقي عند الاستدعاء. هذا هو أساس البرمجة العامة في Swift.

\n\n

الأنواع العامة (Generic Types): إنشاء مكدس (Stack) عالمي خاص بنا

\n\n

الأصناف العامة في Swift لا تعمل فقط مع الدوال، بل مع الأنواع بأكملها. دعنا ننشئ هيكل Stack - المثال الكلاسيكي لهيكل البيانات LIFO (آخر دخول، أول خروج).

\n\n
struct Stack<Element> {\n    private var items: [Element] = []\n    \n    mutating func push(_ item: Element) {\n        items.append(item)\n    }\n    \n    mutating func pop() -> Element? {\n        return items.popLast()\n    }\n    \n    func peek() -> Element? {\n        return items.last\n    }\n    \n    var count: Int {\n        return items.count\n    }\n}\n\n// الاستخدام:\nvar intStack = Stack<Int>()\nintStack.push(1)\nintStack.push(2)\nintStack.push(3)\nprint(intStack.pop() ?? 0) // 3\n\nvar stringStack = Stack<String>()\nstringStack.push("Swift")\nstringStack.push("Generics")\nprint(stringStack.peek() ?? "") // "Generics"
\n\n

لاحظ: النوع Element نحدده بين قوسين زاويتين عند تعريف الهيكل. عند إنشاء نسخة، نحدده - Stack<Int> أو Stack<String>. المترجم يضمن أنك لن تضع عن طريق الخطأ سلسلة نصية في مكدس الأعداد الصحيحة.

\n\n

Protocol مع associatedtype: الأصناف العامة للبروتوكولات

\n\n

في Swift، لا يمكن للبروتوكولات أن تحتوي على معاملات عامة (generic parameters) بشكل مباشر. بدلاً من ذلك، نستخدم

المدونات

توصيات الكتب