ما هي الأدوية الجنيسة في Swift ولماذا نحتاج إليها
Generics (البرمجة العامة) هي واحدة من أقوى ميزات لغة Swift. إنها تتيح لك كتابة كود مرن وقابل لإعادة الاستخدام يعمل مع أي نوع بيانات مع الحفاظ على الكتابة الصارمة. بدلاً من إنشاء دوال أو هياكل منفصلة لأنواع Int و String و Double وغيرها، تكتب كودًا عامًا واحدًا يتكيف مع النوع المحدد أثناء التجميع.
تخيل أنك بحاجة لكتابة دالة تتبادل قيمتين. بدون Generics، سيتعين عليك إنشاء تحميلات زائدة لكل نوع:
func swapInts(_ a: inout Int, _ b: inout Int) { let temp = a a = b b = temp}
func swapStrings(_ a: inout String, _ b: inout String) { let temp = a a = b b = temp}مع Generics يتم ذلك بسطر واحد:
func swapValues<T>(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp}
var x = 10, y = 20swapValues(&x, &y) // يعمل مع Int
var str1 = "Hello", str2 = "World"swapValues(&str1, &str2) // يعمل مع Stringالمزايا الرئيسية لـ Generics
- أمان الأنواع: يتحقق المترجم من الأنواع في مرحلة التجميع، مما يستبعد أخطاء وقت التشغيل
- إعادة استخدام الكود: الكود المكتوب مرة واحدة يعمل مع أي أنواع
- الأداء: يتم تنفيذ Generics في Swift على مستوى المترجم، دون فقدان سرعة التنفيذ
- قابلية القراءة: يقلل من تكرار الكود ويجعله أكثر إيجازًا
الدوال العامة ومعاملات النوع
يتم تعريف الدالة العامة باستخدام الأقواس الزاوية <>، والتي بداخلها يتم تحديد معامل النوع (عادةً ما يُرمز له بالحرف T، ولكن يمكن استخدام أي أسماء). يصبح معامل النوع placeholder يتم استبداله بالنوع الفعلي عند استدعاء الدالة.
مثال: البحث عن عنصر في مصفوفة
func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int? { for (index, element) in array.enumerated() { if element == value { return index } } return nil}
let numbers = [1, 5, 3, 12, 7]if let index = findIndex(of: 12, in: numbers) { print("مؤشر الرقم 12: \\(index)") // مؤشر الرقم 12: 3}
let names = ["Анна", "Борис", "Виктор"]if let index = findIndex(of: "Борис", in: names) { print("مؤشر الاسم Борис: \\(index)") // مؤشر الاسم Борис: 1}لاحظ القيد T: Equatable. هذا هو type constraint — نطلب أن يدعم النوع T بروتوكول Equatable، وإلا فإن عملية المقارنة == ستكون مستحيلة.
الأنواع العامة: الهياكل، الكلاسات، والتعدادات
تعمل Generics ليس فقط مع الدوال ولكن أيضًا مع الأنواع المخصصة. هذا يسمح بإنشاء حاويات بيانات عامة.
إنشاء Stack عام
المثال الكلاسيكي هو هيكل بيانات Stack (المكدس)، الذي يعمل مع أي نوع:
struct Stack<Element> { private var items: [Element] = [] mutating func push(_ item: Element) { items.append(item) } @discardableResult mutating func pop() -> Element? { return items.popLast() } func peek() -> Element? { return items.last } var isEmpty: Bool { return items.isEmpty }}
// الاستخدامvar intStack = Stack<Int>()intStack.push(10)intStack.push(20)print(intStack.pop() ?? "") // 20
var stringStack = Stack<String>()stringStack.push("Swift")stringStack.push("Generics")print(stringStack.pop() ?? "") // Genericsالتعدادات العامة
يمكن أن تكون التعدادات أيضًا