هل من الممكن إضافة قيود الكتابة إلى ملحق مطابقة بروتوكول Swift؟




generics (2)

أرغب في تمديد Array لإضافة التوافق إلى بروتوكول جديد - ولكن فقط للصفائف التي تتوافق عناصرها مع بروتوكول معين.

بشكل عام ، أرغب في الحصول على أنواع (سواء كانت بروتوكولات أو أنواع محددة) مع معلمات كتابة تنفذ بروتوكولًا فقط عندما تتطابق معلمات الكتابة مع قيود معينة.

اعتبارا من Swift 2.0 ، يبدو أن هذا مستحيل. هل هناك طريقة أفتقدها؟

مثال

لنفترض أن لدينا بروتوكول Friendly :

protocol Friendly {
    func sayHi()
}

يمكننا تمديد الأنواع الحالية لتنفيذه:

extension String: Friendly {
    func sayHi() {
        print("Greetings from \(self)!")
    }
}

"Sally".sayHi()

يمكننا أيضًا توسيع Array لتنفيذ sayHi() عندما تكون جميع عناصره Friendly :

extension Array where Element: Friendly {
    func sayHi() {
        for elem in self {
            elem.sayHi()
        }
    }
}

["Sally", "Fred"].sayHi()

في هذه المرحلة ، يجب أن يقوم النوع [Friendly] نفسه بتطبيق Friendly ، لأنه يفي بمتطلبات البروتوكول. ومع ذلك ، لا يتم تجميع هذا الرمز :

extension Array: Friendly where Element: Friendly {
    func sayHi() {
        for elem in self {
            elem.sayHi()
        }
    }
}

رسالة الخطأ هي "امتداد من النوع" Array "مع قيود لا يمكن أن يكون شرط الميراث ،" ويبدو أن إغلاق الباب نهائيا على هذا النهج المباشر.

هل هناك حل غير مباشر؟ بعض خدعة ذكية يمكنني استخدامها؟ ربما هناك طريقة تتضمن تمديد SequenceType بدلاً من Array ؟

حل العمل من شأنه أن يجعل هذا الرمز ترجمة:

let friendly: Friendly = ["Foo", "Bar"]

تحديث: هذا قد هبط في Swift 4.1 ، وهو شيء من الجمال!

extension Array: Friendly where Element: Friendly مثال extension Array: Friendly where Element: Friendly يجمع الآن كما هو موضح في السؤال الأصلي.


تحرير: كما لوحظ في السؤال المحدث ، أصبح هذا ممكنًا منذ Swift 4.1

هذا غير ممكن حاليًا في Swift (اعتبارًا من Xcode 7.1). كما يشير الخطأ ، لا يمكنك تقييد توافق البروتوكول ("جملة الوراثة") على امتداد مقيد بالنوع. ربما يوما ما. لا أعتقد أن هناك أي سبب وجيه لذلك ليكون مستحيلًا ، لكنه لم يتم تنفيذه حاليًا.

أقرب ما يمكنك الحصول عليه هو إنشاء نوع مجمّع مثل:

struct FriendlyArray<Element: Friendly>: Friendly {
    let array: [Element]
    init(_ array: [Element]) {
        self.array = array
    }
    func sayHi() {
        for elem in array {
            elem.sayHi()
        }
    }
}

let friendly: Friendly = FriendlyArray(["Foo", "Bar"])

(من المحتمل أنك تريد توسيع FriendlyArray ليكون CollectionType .)

للحصول على قصة من أصل الخاصة إلى الجنون من محاولة جعل هذا العمل ، وزحف بلدي مرة أخرى من الحافة ، راجع NSData ، صديقي القديم .








generics