English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
تقدم Swift الأنواع العامة لكتابة وظائف وأنواع قابلة للتكرار ومرونة.
مكتبة Swift القياسية مبنية من خلال الكود العام.
مصفوفات Swift و قوائمها هي مجموعات عامة.
يمكنك إنشاء مصفوفة من نوع Int، أو مصفوفة من نوع String، أو حتى أي مصفوفة من أنواع البيانات الأخرى الخاصة بلغة Swift.
المثال التالي هو وظيفة غير عامة تُستخدم لتبادل قيم نوع Int:
// تعريف دالة تبادل قيمين func swapTwoInts(_ a: inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA } var numb1 = 100 var numb2 = 200 print("بيانات تبادل قبل التبادل: \(numb1) و \(numb2)") swapTwoInts(&numb1, &numb2) print("البيانات بعد التبادل: \(numb1) و \(numb2)")
نتيجة تنفيذ البرنامج أعلاه هي:
بيانات تبادل قبل التبادل: 100 و 200 البيانات بعد التبادل: 200 و 100
المثال أعلاه يستخدم فقط لتبادل قيم نوع Int. إذا كنت ترغب في تبادل قيم نوع String أو Double، يجب عليك كتابة وظيفة جديدة مناسبة، مثل swapTwoStrings(_:_:) و swapTwoDoubles(_:_:)، كما هو موضح أدناه:
func swapTwoStrings(_ a: inout String, _ b: inout String) { let temporaryA = a a = b b = temporaryA } func swapTwoDoubles(_ a: inout Double, _ b: inout Double) { let temporaryA = a a = b b = temporaryA }
من خلال النظر في الكود أعلاه، يمكن ملاحظة أن الكود الخاص بالوظائف متطابق، ولكن الفرق يكمن في النوع، في هذه الحالة يمكننا استخدام الأنواع العامة لتجنب كتابة الكود مرة أخرى.
استخدام الأسماء النوعية المؤقتة (في هذا المثال باستخدام الحرف T) لتعويض الأسماء النوعية الفعلية (مثل Int،String أو Double).
func swapTwoValues<T>(_ a: inout T, _ b: inout T)
يتبع swapTwoValues نوعًا مؤقتًا (T) ويُقيد بين الدوائر البارزة (<T>
(). هذا العلامة الديناميكية تخبر Swift أن T هو اسم نوع مؤقت لـ swapTwoValues(_:_:) دالة التعريف، لذا لن يبحث Swift عن نوع T الفعلي.
النموذج التالي هو دالة قابلة للتعميم exchange تستخدم لتبادل قيم Int و String:
// تعريف دالة تبادل قيمين func swapTwoValues<T>(_ a: inout T, _ b: inout T) { let temporaryA = a a = b b = temporaryA } var numb1 = 100 var numb2 = 200 print("البيانات قبل التبادل: \(numb1) و \(numb2)") swapTwoValues(&numb1, &numb2) print("البيانات بعد التبادل: \(numb1) و \(numb2)") var str1 = "A" var str2 = "B" print("البيانات قبل التبادل: \(str1) و \(str2)") swapTwoValues(&str1, &str2) print("البيانات بعد التبادل: \(str1) و \(str2)")
نتيجة تنفيذ البرنامج أعلاه هي:
البيانات قبل التبادل: 100 و 200 البيانات بعد التبادل: 200 و 100 البيانات قبل التبادل: A و B البيانات بعد التبادل: B و A
Swift يسمح لك بتعريف أنواع قابلة للتعميم الخاصة بك.
النوع المخصص للفئات، الهياكل والقوائم يمكن استخدامها لأي نوع، مثل استخدام Array و Dictionary.
دعنا نكتب الآن نوع مجموعة قابلة للتعميم يُدعى Stack (القاع)، يسمح القاع بإضافة عناصر جديدة إلى نهاية المجموعة (يُدعى إدراج)، ويُسمح أيضًا بإزالة العناصر من النهاية (يُدعى إزالة).
التفسير من اليسار إلى اليمين في الصورة كالتالي:
ثلاث قيم في القاع.
تم دفع القيمة الرابعة إلى أعلى القاع.
هناك أربع قيم في القاع، القيمة التي تم إدخالها مؤخرًا في القاع هي التي في القمة.
القيمة الأعلى في القاع يتم إزالتها، أو يمكن القول أن يتم إزالتها من القاع.
بعد إزالة قيمة واحدة، أصبحت القاع تحتوي الآن على ثلاثة قيم فقط.
النموذج التالي هو إصدار غير عام من القاع، لنوع القاع من نوع Int على سبيل المثال:
struct IntStack {}} var items = [Int]() mutating func push(_ item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() } }
يستخدم هذا المركب خاصية Array تُدعى items لتخزين القيم. يقدم Stack طريقتين: push(_:) و pop()، لضغط القيمة في المخزن وإزالتها منه. يتم تسمية هذه الطرق mutating لأنها تحتاج إلى تعديل قائمة items للمركب.
مركب IntStack في الأعلى يمكن استخدامه فقط لنوع Int. ومع ذلك، يمكن تعريف مركب Stack عام يمكنه التعامل مع أي نوع قيمة.
إليك نسخة من نفس الكود بنسخة عامة:
struct Stack<Element> { var items = [Element]() mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } } var stackOfStrings = Stack<String>() print("إدخال عنصر النص إلى المجموعة:") stackOfStrings.push("google") stackOfStrings.push("w3codebox") print(stackOfStrings.items); let deletetos = stackOfStrings.pop() print("العنصر المخرج: " + deletetos) var stackOfInts = Stack<Int>() print("إدخال العنصر الصحيح في المخزن: ") stackOfInts.push(1) stackOfInts.push(2) print(stackOfInts.items);
نتيجة تنفيذ المثال:
إدخال عنصر النص إلى المجموعة: ["google", "w3codebox"] العنصر المخرج: w3codebox إدخال العنصر الصحيح في المخزن: [1, 2]
Stack تقريباً مشابهة لـ IntStack، يتم استبدال النوع الحقيقي Int بنوع المعلمة Element.
في المثال أعلاه، تم استخدام Element في ثلاثة أماكن كموضح:
لإنشاء items مستخدم خاصية Element نوع النمط الفارغ للقائمة لتحديثها.
محدد push(_:) المتغير الوحيد في الطريقة item النوع المحدد يجب أن يكون Element النوع.
محدد pop() يجب أن يكون نوع العائد للمتغير في الطريقة Element النوع.
عندما تقوم بتوسيع نوع عام (باستخدام الكلمة المفتاحية extension)، لا تحتاج إلى تقديم قائمة من معلمات النوع في التعريف التوسيعي. إنه أكثر مرونة أن يمكن استخدام قائمة معلمات النوع المعلن عنها في التعريف الأصلي في التوسيع، وستستخدم هذه الأسماء من النوع الأصلي كمراجع للمعلمات النوعية في التعريف الأصلي.
النموذج التوضيحي التالي يوسع النوع العام Stack، ويضيف خاصية حسابية قابلة للقراءة تُدعى topItem، ستعود بجعل العنصر الحالي في قمة المخزن دون ازالته من المخزن:
struct Stack<Element> { var items = [Element]() mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } } extension Stack {}} var topItem: Element? { return items.isEmpty ? nil : items[items.count - 1] } } var stackOfStrings = Stack<String>() print("إدخال عنصر النص إلى المجموعة:") stackOfStrings.push("google") stackOfStrings.push("w3codebox") if let topItem = stackOfStrings.topItem { print("العنصر الأعلى في المجموعة هو: \(topItem).") } print(stackOfStrings.items)
في هذا المثال، سيعود topItem الخاصية إلى قيمة اختيارية من نوع Element. عند تكون المجموعة فارغة، سيكون topItem يعود إلى nil؛ عند عدم تكون المجموعة فارغة، سيكون topItem يعود إلى العنصر الأخير في مجموعة items.
نتيجة تنفيذ البرنامج أعلاه هي:
إدخال عنصر النص إلى المجموعة: العنصر الأعلى في المجموعة هو: w3codebox. ["google", "w3codebox"]
يمكننا أيضًا تحديد نوع مرتبط من خلال امتداد نوع موجود.
على سبيل المثال، نوع Array في Swift يقدم طريقة append(_:)، خاصية count، ومؤشر يقبل قيمة نوع Int لاسترجاع العنصر. هذه الميزات تتناسب مع آراء التوقيع Container، لذا يمكنك بسهولة إعلان أن Array يتخذ هذا الاتفاق لإضافة امتداد إلى Array.
في هذا المثال، قم بإنشاء امتداد فارغ فقط:
extension Array: Container {}
رأي نوع يحدد نوع السمة يجب أن يورث من فئة معينة أو يتوافق مع آراء التوقيع أو مجموعة آراء التوقيع.
يمكنك كتابة رأي نوع وراء اسم نوع السمة، من خلال تقسيمها بالكومي، كجزء من سلسلة آراء التوقيع. الجملة الأساسية لرأي نوع التوقيع هذا الذي يؤثر على الدالة الجينرية كالتالي (مثل جملة نوع الجينرية):
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // هنا جسم الدالة الجينرية }
هذه الدالة لها نوعان من آراء التوقيع. الرأي الأول نوع T، يتطلب أن يكون نوع T نوع فرعي لـ SomeClass؛ الرأي الثاني نوع U، يتطلب أن يكون نوع U نوع يتوافق مع آراء التوقيع SomeProtocol.
// دالة غير عامة، العثور على مؤشر نص معين في اللوحة func findIndex(ofString valueToFind: String, in array: [String]) -> Int? { for (index, value) in array.enumerated() { if value == valueToFind { // إذا تم العثور على العنصر، يتم العودة إلى قيمة المؤشر return index } } return nil } let strings = ["google", "weibo", "taobao", "w3codebox", "facebook"] if let foundIndex = findIndex(ofString: "w3codebox", in: strings) { print("يبلغ مؤشر w3codebox \(foundIndex)") }
تبدأ الأنماط من الصفر.
نتيجة تنفيذ البرنامج أعلاه هي:
يبلغ مؤشر w3codebox 3
يستخدم Swift كلمة المفتاح associatedtype لتحديد نوع مرتبط في أمثلة.
يحدد هذا المثال معاهدة Container، التي تحدد نوعًا مرتبطًا يسمى ItemType.
تحدد معاهدة Container ثلاث وظائف يجب أن توفرها أي نوع يتبع معاهدة Container. يمكن للنوع الذي يتبع المعاهدة توفير وظائف إضافية أخرى إذا كان يتوافق مع هذه الثلاثة شروط.
//معاهدة Container protocol Container { associatedtype ItemType //إضافة عنصر جديد إلى الحاوية mutating func append(_ item: ItemType) //الحصول على عدد العناصر داخل الحاوية var count: Int { get } //استرجاع كل عنصر داخل الحاوية باستخدام مؤشر من نوع Int subscript(i: Int) -> ItemType { get } } // هيكل Stack يتبع معاهدة Container struct Stack<Element>: Container { //جزء التنفيذ الأصلي لـ Stack<Element> var items = [Element]() mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } //جزء التنفيذ لمعاهدة Container mutating func append(_ item: Element) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> Element { return items[i] } } var tos = Stack<String>() tos.push("google") tos.push("w3codebox") tos.push("taobao") // قائمة العناصر print(tos.items) // عدد العناصر print( tos.count)
نتيجة تنفيذ البرنامج أعلاه هي:
["google", "w3codebox", "taobao"] 3
تضمن القيود النوعية التأكد من أن النوع يتوافق مع قيود دالة أو فئة عامة.
يمكنك تعريف قيود المعلمات في قائمة المعلمات من خلال جملة where.
يمكنك كتابة جملة where، تتبع قائمة معلمات النوع، حيث تشمل جملة where قيودًا على النوع المرتبط، وكذلك (أو) علاقات مساواة بين النوع والنوع المرتبط.
النموذج التطبيقي التالي يحدد دالة عامة تسمى allItemsMatch، تستخدم لتحقق من أن عينيتين من نوع Container تحتويان على نفس الترتيب من العناصر المتشابهة.
إذا كانت جميع العناصر تتطابق، فعددلها إلى true، وإلا فإنه يعدلها إلى false.
//معاهدة Container protocol Container { associatedtype ItemType //إضافة عنصر جديد إلى الحاوية mutating func append(_ item: ItemType) //الحصول على عدد العناصر داخل الحاوية var count: Int { get } //استرجاع كل عنصر داخل الحاوية باستخدام مؤشر من نوع Int subscript(i: Int) -> ItemType { get } } ///// نوع泛ومي TOS الذي يتبع معاهدة Container struct Stack<Element>: Container { //جزء التنفيذ الأصلي لـ Stack<Element> var items = [Element]() mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } //جزء التنفيذ لمعاهدة Container mutating func append(_ item: Element) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> Element { return items[i] } } //توسيع، إستخدام Array كحاوية extension Array: Container {} func allItemsMatch<ItemT1: Container, ItemT2: Container> { (_ someContainer: ItemT1, _ anotherContainer: ItemT2) -> Bool حيث ItemT1.ItemType == ItemT2.ItemType, ItemT1.ItemType: Equatable { //تحقق من أن كلا الحاويين يحتويان على نفس عدد العناصر إذا كان عدد عناصر someContainer غير متساوي مع عدد عناصر anotherContainer { return false } // التحقق من كل زوج من العناصر إذا كانا متطابقين for i in 0..<someContainer.count { if someContainer[i] != anotherContainer[i] { return false } } // جميع العناصر مطابقة، العودة إلى true return true } var tos = Stack<String>() tos.push("google") tos.push("w3codebox") tos.push("taobao") var aos = ["google", "w3codebox", "taobao"] if allItemsMatch(tos, aos) { print("التنسيق مع جميع العناصر") } print("العدم التطابق للعناصر") }
نتيجة تنفيذ البرنامج أعلاه هي:
التنسيق مع جميع العناصر