Generic — جوهر الأنواع العامة ومعلمات T

المؤلف: IT Sectr نُشر: 2026-06-18 وقت القراءة: 10 دق

Generic (البرمجة العامة) — هي آلية Swift تسمح بكتابة الأنواع والدوال بنوع معلم . بدلاً من تكرار الكود لـ Int، String والهياكل المخصصة، ينشئ المطور حلاً عاماً واحداً يعمل مع أي نوع، محافظاً على التحديد الصارم للأنواع. يستبدل المترجم النوع المحدد عند نقطة الاستخدام، مما يضمن الأمان دون فقدان الأداء. وفقاً لـ Swift Book, 2025، تعد المعلمات العامة واحدة من الميزات الرئيسية للغة، التي تشكل أساس المكتبة القياسية و SwiftUI.

النقاط الرئيسية

  • Generic — آلية البرمجة العامة بمعلمات أنواع
  • الدوال بمعلمات عامة تعمل مع أي نوع دون تكرار الكود
  • قيود where تضيق نطاق العام للأنواع التي تستوفي الشروط
  • Associated Types في البروتوكولات تسمح للبروتوكولات بأن تكون عامة
  • المترجم يولّد كوداً متخصصاً لكل نوع محدد

ما هو Generic في Swift؟

Generic (نوع عام) — هو تركيب نحوي في Swift يسمح بكتابة كود مرن قابل لإعادة الاستخدام مع تحديد الأنواع. بدلاً من نوع محدد، يكتب مكان منتظر في أقواس زاوية — عادة ، ولكن يمكن استخدام أي اسم. تشكل العامة أساس SwiftUI (View، some View)، المكتبة القياسية (Array، Optional) و Combine.

لماذا نحتاج العامة

بدون العامة، سيكون عليك كتابة دوال منفصلة لكل نوع: swapInts، swapStrings، swapDates. تستبدل دالة عامة swap الثلاث متغيرات بإعلان واحد. يقلل هذا من التكرار، يحسن القراءة ويقلل احتمالية الأخطاء عند نسخ الكود.

swift
func swapValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 10
var y = 20
swapValues(&x, &y)

يولد مترجم Swift كوداً متخصصاً لكل استخدام محدد للعام. هذا يعني أن الدالة العامة swapValues ليس لها حمل زائد مقارنة بدالة مكتوبة يدوياً لـ Int. Swift لا يستخدم محو الأنواع مثل Java — العامة موجودة في وقت الترجمة ووقت التنفيذ على السواء (وإن كان التحسين يمكن أن يخصصها).

الدوال العامة بمعلمة T

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

معلمات أنواع متعددة

يمكن أن تحتوي الدالة على معلمات عامة متعددة. على سبيل المثال، تأخذ الدالة findKey قاموساً بمفاتيح K وقيم V. كل معلم نوع فريد ويمكن استخدامه في القيود.

swift
func findKey<K: Hashable, V>(
    for value: V,
    in dictionary: [K: V]
) -> K? where V: Equatable {
    for (key, dictValue) in dictionary {
        if dictValue == value {
            return key
        }
    }
    return nil
}

تضمن القيود K: Hashable و where V: Equatable أنه يمكن استدعاء findKey فقط بقاموس مفاتيحه قابلة للتجزئة وقيمه قابلة للمقارنة. هذه القيود ليست بيروقراطية بل ضرورة: بدون Hashable لا يمكنك فهرسة البحث عن المفتاح، وبدون Equatable لا يمكنك مقارنة value مع dictValue.

قيود الأنواع عبر where

where — هي كلمة مفتاحية في Swift تفرض قيوداً إضافياً على المعلمات العامة. خلافاً لتحديد بروتوكول بسيط في أقواس زاوية ()، تسمح where بتعبير عن شروط أكثر تعقيداً: الامتثال لبروتوكولات متعددة، العلاقات بين معلمات الأنواع وتحسين الأنواع المرتبطة.

نحو where

تكتب جملة where بعد توقيع الدالة أو النوع قبل القوس المفتوح. في where يمكنك تحديد أن T: Comparable & Hashable (متوافق مع بروتوكولين في نفس الوقت)، أو أن T.U == Int (تحديد نوع مرتبط).

swift
protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
}

extension Container where Item: Comparable {
    func isSorted() -> Bool {
        // Implementation available only if Item: Comparable
        return true
    }
}

الإمتداد بـ where يضيف طرقاً فقط للأنواع التي تستوفي الشرط. Container سيحصل على طريقة isSorted، أما Container فلن يحصل، لأن Any ليس Comparable. هذه آلية قوية للوظائف الشرطية.

Associated Types في البروتوكولات

Associated Types (الأنواع المرتبطة) — هي طريقة لجعل البروتوكول عاماً دون تحديد نوع محدد في مرحلة التصريح. بدلاً من ، يصرح البروتوكول عن associatedtype، وهو ما يتم تحديده في التنفيذ. هذا مهم بشكل خاص للمجموعات: بروتوكول Sequence لا يعرف ما هي العناصر التي ستحتويها المتتابعة.

ربط الأنواع المرتبطة عبر where

باستخدام where يمكنك إنشاء علاقات بين الأنواع المرتبطة لبروتوكولات مختلفة. على سبيل المثال، يمكنك المطالبة بأن يتطابق Item من بروتوكول مع Iterator.Element من آخر. هذا يضمن التوافق بين الأنواع على مستوى الترجمة.

swift
protocol StackProtocol {
    associatedtype Element
    mutating func push(_ item: Element)
    mutating func pop() -> Element?
}

struct IntStack: StackProtocol {
    typealias Element = Int
    private var items: [Int] = []
    
    mutating func push(_ item: Int) { items.append(item) }
    mutating func pop() -> Int? { items.popLast() }
}

IntStack يحدد Element كـ Int باستخدام typealias. يتحقق المترجم من أن جميع متطلبات البروتوكول تنجز بهذا النوع. بدون الأنواع المرتبطة، كان عليك كتابة StackProtocol ببروتوكول عام، ولكن Swift يستخدم الأنواع المرتبطة للاتساق مع جسور Objective-C وقراءة أفضل.

Generic في الإمتدادات والفهارس

الإمتدادات العامة تسمح بإضافة طرق إلى نوع عام مع قيود إضافية. هذا هو نمط ـ“المطابقة الشرطية”، حيث يحصل النوع على وظائف فقط تحت ظروف معينة. يمكن أن تكون الفهارس عامة أيضاً.

الفهرس العام

يمكن أن يكون الفهرس عاماً: يقبل معلمات عامة في أقواس زاوية. هذا مفيد للوصول الآمن إلى المجموعات بفهارس عشوائية، حيث يمكن أن يكون الفهرس من أنواع مختلفة.

swift
extension Array where Element: Numeric {
    func sum() -> Element {
        return reduce(0, +)
    }
}

extension Array {
    subscript<Indices: Sequence>(indices: Indices) -> [Element]
        where Indices.Element == Int {
        return indices.map { self[$0] }
    }
}

هذا البناء يوفر تركيباً قوياً: طريقة sum تظهر فقط في المصفوفات الرقمية، والفهرس بفهارس عشوائية يعمل مع أي تسلسل من الفهارس الصحيحة. يدير المترجم رؤية هذه الأعضاء بناءً على شروط where.

الأخطاء الشائعة عند العمل مع العام

الأخطاء عند استخدام العامة غالباً ما ترتبط بقيود غير صحيحة أو محاولة استخدام العامة حيث يكفي نوع محدد. دعنا نستعرض ثلاث سيناريوهات شائعة يواجهها المطورون.

التحديد المفرط

إضافة معلمات عامة حيث يكفي نوع محدد هو نمط ضد. إذا كانت الدالة تعمل دائماً مع String، لا داعي لجعلها . هذا يعقد الكود دون فائدة. تبرر العامة عندما يتغير النوع حقاً، ليس لــ“مرونة مستقبلية” مجردة.

فقدان قيد where

استدعاء طريقة على معلم عام دون تحديد أن الطريقة موجودة هو خطأ. لا يستطيع استدعاء .count إذا لم يتم تحديد أن T: Collection. أضف دائماً قيوداً على معلمات الأنواع، وإلا سيرفض المترجم الكود.

swift
// ❌ Error: value has no count method
func countElements<T>(value: T) -> Int { value.count }

// ✅ Works: T: Collection guarantees count exists
func countElements<T: Collection>(value: T) -> Int { value.count }

الخطأ واضح: العام يمكن أن يكون أي نوع، والمترجم لا يعرف إذا كان له count. يحل قيد Collection المشكلة. بالمثل لـ Equatable، Hashable، Numeric — حدد دائماً البروتوكول إذا كنت تخطط لاستدعاء طرق أو عوامل على المعلم العام.

الأسئلة الشائعة

ما هو Generic في Swift بكلمات بسيطة؟

Generic هو طريقة لكتابة كود يعمل مع أي نوع، دون تكرار نفس المنطق لـ Int، String وأنواع أخرى. بدلاً من نوع محدد، يستخدم مكان ، والذي يستبدل بالنوع الحقيقي عند نقطة الاستخدام.

ما الفرق بين Generic و Any؟

Generic يحافظ على معلومات النوع المحدد عند الترجمة، مما يسمح للمترجم بتحقيق الأنواع وتوليد كود محسن. Any هو محو للأنواع: يمكن تمرير أي قيمة، ولكن يفقد النوع ويتطلب تحويلاً (as?).

كيف تقييد Generic ببروتوكول؟

استخدم التركيب T: SomeProtocol في أقواس زاوية أو جملة منفصلة where T: SomeProtocol. تضمن القيود أن المعلم العام يدعم طرقاً وخصائص محددة.

ما هو Associated Type في بروتوكول؟

Associated Type (associatedtype) هو مكان لنوع داخل البروتوكول. البروتوكول لا يحدد نوعاً محدداً بل يصرح عن associatedtype، الذي يتم تحديده في التنفيذ: Array لديه Element، Dictionary لديه Key و Value.

هل العامة أسرع أم أبطأ من الأنواع المحددة؟

Swift يترجم الكود العام إلى نسخ متخصصة لكل نوع محدد. في الممارسة، دالة عامة لـ Int ليست أبطأ من دالة مكتوبة يدوياً لـ Int. لا يوجد حمل زائد للتجريد.

الملخص

  • Generic — آلية البرمجة العامة بمعلم نوع
  • الدوال والأنواع بمعلمات عامة تستبدل عدة تنفيذات مكررة
  • قيود where تضيق نطاق العامة إلى الشروط الضرورية
  • Associated Types تسمح للبروتوكولات بأن تكون عامة دون تحديد عند التصريح
  • الإمتدادات بـ where تضيف وظائف فقط عند استيفاء الشروط
  • المترجم يولّد كوداً متخصصاً — العامة لا تضيف حملاً زائداً
  • التحديد المفرط هو نمط ضد — استخدم العامة فقط عندما يتغير النوع حقاً

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا