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

مرحبا بالجميع! إننا نشارك معك ترجمة أعدت خصيصًا لطلاب الدورة التدريبية "iOS Developer. دورة متقدمة . " هل لديك قراءة جيدة.



وظيفة عامة ، النوع العام والقيود النوع

ما هي الأدوية الجنيسة؟


عندما يعملون ، أنت تحبهم ، وعندما لا ، تكرههم!

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

سويفت هي لغة آمنة. كلما عملنا مع الأنواع ، نحتاج إلى تحديدها صراحة. على سبيل المثال ، نحتاج إلى وظيفة ستعمل مع أكثر من نوع واحد. يحتوي Swift على أنواع Any و AnyObject ، لكن يجب استخدامها بعناية وليس دائمًا. AnyObject استخدام Any و AnyObject إلى جعل التعليمات البرمجية غير موثوقة ، حيث سيكون من المستحيل تتبع عدم تطابق النوع أثناء AnyObject البرمجي. هذا هو المكان الذي تأتي فيه الأدوية الجنيسة.

يسمح لك الرمز العام بإنشاء وظائف وأنواع بيانات قابلة لإعادة الاستخدام يمكن أن تعمل مع أي نوع يلبي قيودًا معينة ، مع ضمان سلامة الكتابة أثناء التحويل البرمجي. يتيح لك هذا النهج كتابة التعليمات البرمجية التي تساعد على تجنب الازدواجية والتعبير عن وظيفتها بطريقة مجردة واضحة. على سبيل المثال ، تستخدم أنواع مثل Array و Set و Dictionary عامة لتخزين العناصر.

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

 let intArray = [1, 2, 3, 4] let stringArray = [a, b, c, d] func printInts(array: [Int]) { print(intArray.map { $0 }) } func printStrings(array: [String]) { print(stringArray.map { $0 }) } 

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

تاريخ الوراثة في سويفت




وظائف عامة


وظيفة عامة يمكن أن تعمل مع أي معلمة عالمية من نوع T لا يذكر اسم النوع شيئًا عما يجب أن يكون ، لكنه يقول أن كلا الصفيفين يجب أن يكونا من النوع ، بغض النظر عن ماهية يتم تحديد النوع نفسه المراد استخدامه بدلاً من كل مرة تسمى فيها وظيفة print( _: ) .

 func print<T>(array: [T]) { print(array.map { $0 }) } 

الأنواع العامة أو تعدد الأشكال حدودي


النوع العام T من المثال أعلاه هو معلمة type. يمكنك تحديد العديد من معلمات الكتابة عن طريق كتابة العديد من أسماء معلمات الكتابة في أقواس زاوية ، مفصولة بفواصل.

إذا نظرت إلى Array و Dictionary <Key ، Element> ، ستلاحظ أنهما قاما بتسمية معلمات type ، وهي Element و Key و Element ، والتي تتحدث عن العلاقة بين معلمة type والنوع العام أو الوظيفة التي يتم استخدامها .

ملاحظة: أعط دائمًا أسماء لكتابة معلمات في تدوين CamelCase (على سبيل المثال ، T و TypeParameter ) لإظهار أنها اسم للنوع ، وليست قيمة.

أنواع عامة


هذه فئات مخصصة وهياكل وتعدادات يمكن أن تعمل مع أي نوع ، على غرار المصفوفات والقواميس.

دعنا نخلق كومة

 import Foundation enum StackError: Error { case Empty(message: String) } public struct Stack { var array: [Int] = [] init(capacity: Int) { array.reserveCapacity(capacity) } public mutating func push(element: Int) { array.append(element) } public mutating func pop() -> Int? { return array.popLast() } public func peek() throws -> Int { guard !isEmpty(), let lastElement = array.last else { throw StackError.Empty(message: "Array is empty") } return lastElement } func isEmpty() -> Bool { return array.isEmpty } } extension Stack: CustomStringConvertible { public var description: String { let elements = array.map{ "\($0)" }.joined(separator: "\n") return elements } } var stack = Stack(capacity: 10) stack.push(element: 1) stack.push(element: 2) print(stack) stack.pop() stack.pop() stack.push(element: 5) stack.push(element: 3) stack.push(element: 4) print(stack) 

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

 enum StackError: Error { case Empty(message: String) } public struct Stack<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 } } extension Stack: CustomStringConvertible { public var description: String { let elements = array.map{ "\($0)" }.joined(separator: "\n") return elements } } var stack = Stack<Int>(capacity: 10) stack.push(element: 1) stack.push(element: 2) print(stack) var strigStack = Stack<String>(capacity: 10) strigStack.push(element: "aaina") print(strigStack) 

قيود النوع العام


نظرًا لأن النوع العام يمكن أن يكون من أي نوع ، فلا يمكنك القيام به كثيرًا. من المفيد في بعض الأحيان تطبيق قيود على الأنواع التي يمكن استخدامها مع وظائف عامة أو أنواع عامة. تشير قيود النوع إلى أن المعلمة type يجب أن تتطابق مع بروتوكول أو تكوين بروتوكول معين.

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

 func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // function body goes here } 

في الأساس ، أنشأنا مجموعة من النوع T ، لكن لا يمكننا مقارنة مجموعتين ، لأن الأنواع هنا لا تتطابق مع Equatable . نحن بحاجة إلى تغيير هذا لاستخدام Stack< T: Equatable > .

كيف تعمل الأدوية الجنيسة؟ لنلقِ نظرة على مثال.

 func min<T: Comparable>(_ x: T, _ y: T) -> T { return y < x ? y : x } 

يفتقر المحول البرمجي إلى شيئين ضروريين لإنشاء رمز الوظيفة:

  • أحجام المتغيرات من النوع T ؛
  • عناوين الحمل الزائد المحدد للوظيفة <، والتي يجب استدعاؤها في وقت التشغيل.

كلما واجه المترجم قيمة من النوع عام ، فإنه يضع القيمة في حاوية. تحتوي هذه الحاوية على حجم ثابت لتخزين القيم. في حال كانت القيمة كبيرة جدًا ، يخصصها Swift على الكومة ويخزنها في الحاوية.

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

نهاية الجزء الاول. بالتقليد ، نحن في انتظار تعليقاتكم ، الأصدقاء.

الجزء الثاني

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


All Articles