Est-il possible d’append des contraintes de type à une extension de conformité du protocole Swift?

Je voudrais étendre Array pour append la conformité à un nouveau protocole – mais seulement pour les tableaux dont les éléments eux-mêmes sont conformes à un protocole spécifique.

Plus généralement, je souhaiterais que des types (protocoles ou types concrets) avec des parameters de type implémentent un protocole uniquement lorsque les parameters de type correspondent à certaines contraintes.

À partir de Swift 2.0, cela semble impossible. Y a-t-il un moyen qui me manque?

Exemple

Supposons que nous ayons le protocole Friendly :

 protocol Friendly { func sayHi() } 

Nous pouvons étendre les types existants pour le mettre en œuvre:

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

Nous pouvons également étendre Array pour implémenter sayHi() lorsque tous ses éléments sont Friendly :

 extension Array where Element: Friendly { func sayHi() { for elem in self { elem.sayHi() } } } ["Sally", "Fred"].sayHi() 

À ce stade, le type [Friendly] devrait lui-même implémenter Friendly , car il répond aux exigences du protocole. Cependant, ce code ne comstack pas :

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

Le message d’erreur est «l’extension du type ‘Array’ avec des contraintes ne peut avoir de clause d’inheritance», ce qui semble fermer définitivement la porte à cette approche directe.

Existe-t-il une solution de contournement indirecte? Un truc intelligent que je peux utiliser? Peut-être y a-t-il un moyen d’implémenter SequenceType au lieu de Array ?

Une solution de travail permettrait de comstackr ce code:

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

Mise à jour: Cela a atterri dans Swift 4.1, et c’est une chose de beauté!

L’ extension Array: Friendly where Element: Friendly exemple extension Array: Friendly where Element: Friendly comstack maintenant comme indiqué dans la question d’origine.

Ce n’est pas possible actuellement dans Swift (à partir de Xcode 7.1). Comme l’indique l’erreur, vous ne pouvez pas restreindre la conformité de protocole (“clause d’inheritance”) à une extension de type contrainte. Peut-être un jour. Je ne crois pas qu’il y ait une raison profonde pour que cela soit impossible, mais elle n’est actuellement pas mise en œuvre.

Le plus proche possible est de créer un type de wrapper tel que:

 struct FriendlyArray: Friendly { let array: [Element] init(_ array: [Element]) { self.array = array } func sayHi() { for elem in array { elem.sayHi() } } } let friendly: Friendly = FriendlyArray(["Foo", "Bar"]) 

(Vous voudrez probablement étendre FriendlyArray pour être un CollectionType .)

Pour une histoire de ma propre descente dans la folie d’essayer de faire ce travail et mon retour du bord, voir NSData, My Old Friend .

La bonne nouvelle est que ce que vous demandez pour la Conditional Conformance arrive dans Swift 4.1:

https://swift.org/blog/conditional-conformance/