قوة الأدوية في سويفت. الجزء 2

مساء الخير أيها الأصدقاء. خاصة لطلاب الدورة "iOS Developer. دورة متقدمة "، قمنا بإعداد ترجمة للجزء الثاني من مقال" قوة الوراثة في سويفت ".





الأنواع ذات الصلة ، حيث الجمل والاشتراكات والمزيد ...

في مقال "قوة الوراثة في سويفت. الجزء 1 " وصف وظائف عامة ، وأنواع عامة وقيود النوع. إذا كنت مبتدئًا ، أوصي بأن تقرأ الجزء الأول أولاً لفهم أفضل.

عند تعريف البروتوكول ، يكون من المفيد أحيانًا إعلان نوع أو أكثر من الأنواع ذات الصلة كجزء من التعريف. يحدد النوع المرتبط اسم كعب الروتين للنوع المستخدم كجزء من البروتوكول. لن يتم تحديد النوع الفعلي المستخدم لهذا النوع ذي الصلة حتى يتم استخدام البروتوكول. يتم الإعلان عن الأنواع associatedtype باستخدام الكلمة الأساسية associatedtype .

يمكننا تحديد بروتوكول المكدس الذي أنشأناه في الجزء الأول .

 protocol Stackable { associatedtype Element mutating func push(element: Element) mutating func pop() -> Element? func peek() throws -> Element func isEmpty() -> Bool func count() -> Int subscript(i: Int) -> Element { get } } 

يعرّف البروتوكول Stackable الوظيفة الضرورية التي يجب أن توفرها أي مكدس.

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

دعنا نغير مجموعتنا وفقًا للبروتوكول:

 enum StackError: Error { case Empty(message: String) } protocol Stackable { associatedtype Element mutating func push(element: Element) mutating func pop() -> Element? func peek() throws -> Element func isEmpty() -> Bool func count() -> Int subscript(i: Int) -> Element { get } } public struct Stack<T>: Stackable { public typealias Element = T var array: [T] = [] init(capacity: Int) { array.reserveCapacity(capacity) } public mutating func push(element: T) { array.append(element) } public mutating func pop() -> T? { return array.popLast() } public func peek() throws -> T { guard !isEmpty(), let lastElement = array.last else { throw StackError.Empty(message: "Array is empty") } return lastElement } func isEmpty() -> Bool { return array.isEmpty } func count() -> Int { return array.count } } extension Stack: Collection { public func makeIterator() -> AnyIterator<T> { var curr = self return AnyIterator { curr.pop() } } public subscript(i: Int) -> T { return array[i] } public var startIndex: Int { return array.startIndex } public var endIndex: Int { return array.endIndex } public func index(after i: Int) -> Int { return array.index(after: i) } } extension Stack: CustomStringConvertible { public var description: String { let header = "***Stack Operations start*** " let footer = " ***Stack Operation end***" let elements = array.map{ "\($0)" }.joined(separator: "\n") return header + elements + footer } } var stack = Stack<Int>(capacity: 10) stack.push(element: 1) stack.pop() stack.push(element: 3) stack.push(element: 4) print(stack) 


تمديد نوع موجود للإشارة إلى نوع مرتبط


يمكنك تمديد نوع موجود ليتوافق مع البروتوكول.

 protocol Container { associatedtype Item mutating func append(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get } } extension Array: Container {} 

إضافة قيود إلى النوع المرتبط:


يمكنك إضافة قيود إلى النوع المقترن في البروتوكول لضمان امتثال الأنواع ذات الصلة لهذه القيود.
دعنا نغير بروتوكول Stackable .

 protocol Stackable { associatedtype Element: Equatable mutating func push(element: Element) mutating func pop() -> Element? func peek() throws -> Element func isEmpty() -> Bool func count() -> Int subscript(i: Int) -> Element { get } } 

الآن يجب أن يتطابق نوع عنصر المكدس مع Equatable ، وإلا Equatable خطأ في وقت الترجمة.

قيود البروتوكول العودية:


قد يكون البروتوكول جزءًا من متطلباته الخاصة.

 protocol SuffixableContainer: Container { associatedtype Suffix: SuffixableContainer where Suffix.Item == Item func suffix(_ size: Int) -> Suffix } 

يحتوي Suffix قيود اثنين: يجب أن يتوافق مع بروتوكول SuffixableContainer (يتم تعريف البروتوكول هنا) ، ويجب أن يتطابق نوع Item الخاص به مع نوع Item الحاوية.

يوجد مثال جيد في مكتبة Swift القياسية في Protocol Sequence لتوضيح هذا الموضوع.

اقتراح بشأن قيود البروتوكول العودية: https://github.com/apple/swift-evolution/blob/master/proposals/0157-recursive-protocol-constrict.md

ملحقات النوع العام:


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


 extension Stack { var topItem: Element? { return items.isEmpty ? nil : items[items.count - 1] } } 

عام حيث الفقرة


بالنسبة للأنواع ذات الصلة ، من المفيد تحديد المتطلبات. يتم وصف الشرط بواسطة الشرط العام . يسمح لك بند "عام" where تطلب منك أن يتوافق النوع المرتبط ببروتوكول معين أو أن تكون معلمات نوع معينة وأنواع ذات صلة هي نفسها. عام where تبدأ جملة بكلمة " where ، تليها قيود على الأنواع ذات الصلة أو علاقة المساواة بين الأنواع والأنواع ذات الصلة. عام where يتم كتابة جملة مباشرة قبل دعامة الفتح للنوع أو وظيفة الجسم.

 func allItemsMatch<C1: Container, C2: Container> (_ someContainer: C1, _ anotherContainer: C2) -> Bool where C1.Item == C2.Item, C1.Item: Equatable { } 

ملحقات مع الظروف العامة حيث


يمكنك استخدام عام where جملة كجزء من التمديد. المثال التالي يمتد بنية Stack الكلي من الأمثلة السابقة عن طريق إضافة isTop (_ :) الأسلوب.

 extension Stack where Element: Equatable { func isTop(_ item: Element) -> Bool { guard let topItem = items.last else { return false } return topItem == item } } 

يضيف الملحق الأسلوب isTop (_ :) فقط عندما تدعم العناصر الموجودة على المكدس Equatable. يمكنك أيضا استخدام عام where جملة مع ملحقات البروتوكول. يمكنك إضافة العديد من المتطلبات إلى where بفصلها بفاصلة.

الأنواع المرتبطة بالفقرة العامة حيث:


يمكنك تضمين عام where جملة في النوع المرتبط.

 protocol Container { associatedtype Item mutating func append(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get } associatedtype Iterator: IteratorProtocol where Iterator.Element == Item func makeIterator() -> Iterator } 

بالنسبة للبروتوكول الذي يرث من بروتوكول آخر ، فأنت تضيف قيدًا إلى النوع الموروث الموروث ، بما في ذلك العبارة where عامة في جملة إعلان البروتوكول. على سبيل المثال ، تعلن التعليمة البرمجية التالية عن بروتوكول ComparableContainer الذي يتطلب Item لدعم Comparable :

 protocol ComparableContainer: Container where Item: Comparable { } 

الأسماء المستعارة للنوع العام:


يمكن أن يكون الاسم المستعار للنوع معلمات شائعة. سيظل اسمًا مستعارًا (وهذا يعني أنه لن يقدم نوعًا جديدًا).

 typealias StringDictionary<Value> = Dictionary<String, Value> var d1 = StringDictionary<Int>() var d2: Dictionary<String, Int> = d1 // okay: d1 and d2 have the same type, Dictionary<String, Int> typealias DictionaryOfStrings<T : Hashable> = Dictionary<T, String> typealias IntFunction<T> = (T) -> Int typealias Vec3<T> = (T, T, T) typealias BackwardTriple<T1,T2,T3> = (T3, T2, T1) 

في هذه الآلية ، لا يمكن استخدام قيود إضافية على معلمات الكتابة.
مثل هذا الرمز لن يعمل:

 typealias ComparableArray<T where T : Comparable> = Array<T> 

superscripts عامة


يمكن أن يستخدم المشتركون الآلية العامة ويتضمن جملة where العامة. تكتب اسم الكتابة بين أقواس زاوية بعد الحرف subscript ، وتكتب الجملة where مباشرة قبل قوس الفتح في نص الرسالة.

 extension Container { subscript<Indices: Sequence>(indices: Indices) -> [Item] where Indices.Iterator.Element == Int { var result = [Item]() for index in indices { result.append(self[index]) } return result } } 

التخصص العام


التخصص العام يعني أن المترجم يستنسخ نوعًا أو وظيفة عامة ، مثل Stack < T > ، لنوع معين من المعلمات ، مثل Int. يمكن بعد ذلك تحسين هذه الوظيفة المتخصصة خصيصًا لـ Int ، بينما ستتم إزالة كل ما هو ضروري. تسمى عملية استبدال معلمات النوع بوسائط الكتابة في وقت الترجمة التخصص .

من خلال تخصيص الوظيفة العامة لهذه الأنواع ، يمكننا التخلص من تكاليف الإرسال الافتراضي ، والمكالمات المضمنة ، عند الضرورة ، والقضاء على النفقات العامة للنظام العام.

مشغل الزائد


لا تعمل الأنواع العامة مع المشغلين افتراضيًا ، لذلك تحتاج إلى بروتوكول.

 func ==<T: Equatable>(lhs: Matrix<T>, rhs: Matrix<T>) -> Bool { return lhs.array == rhs.array } 


شيء مثير للاهتمام حول الأدوية


لماذا لا يمكنك تحديد خاصية مخزنة ثابتة لنوع عام؟

سيتطلب ذلك تخزينًا منفصلاً لخصائص كل تخصص عام (T).

موارد للدراسة المتعمقة:


https://github.com/apple/swift/blob/master/docs/Generics.rst
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md
https://developer.apple.com/videos/play/wwdc2018/406/
https://www.youtube.com/watch؟v=ctS8FzqcRug
https://medium.com/@vhart/protocols-generics-and-existential-containers-wait-what-e2e698262ab1


هذا كل شيء. أراك في الدورة .

Source: https://habr.com/ru/post/ar463789/


All Articles