web-dev-qa-db-fra.com

Swift "where" Extensions de tableau

À partir de Swift 2.0, il semble que nous pouvons nous rapprocher des extensions de types génériques applicables aux situations prédites.

Bien que nous ne puissions toujours pas faire cela:

protocol Idable {
    var id : String { get }
}

extension Array where T : Idable {
    ...
}

... nous pouvons maintenant le faire:

extension Array {
    func filterWithId<T where T : Idable>(id : String) -> [T] {
    ...
    }
}

... et Swift l'accepte grammaticalement. Cependant, pour la vie de moi, je ne peux pas comprendre comment rendre le compilateur heureux quand je remplis le contenu de l'exemple de fonction. Supposons que je devais être aussi explicite que possible:

extension Array {
    func filterWithId<T where T : Idable>(id : String) -> [T] {
        return self.filter { (item : T) -> Bool in
            return item.id == id
        }
    }
}

... le compilateur n'acceptera pas la fermeture fournie pour filtrer, se plaignant

Impossible d'appeler 'filtre' avec une liste d'arguments de type '((T) -> Bool)'

Similaire si l'élément est spécifié comme idable. Quelqu'un a eu de la chance ici?

26
yo.ian.g
extension Array {
    func filterWithId<T where T : Idable>(id : String) -> [T] {
    ...
    }
}

définit une méthode générique filterWithId() où l'espace réservé générique T est limité à Idable. Mais cette définition introduit un espace réservé local T qui est complètement indépendant du type d'élément de tableau T (et le masque dans la portée de la méthode).

Vous avez donc pas spécifié que les éléments du tableau doivent être conformes à Idable, et c'est la raison pour laquelle vous ne pouvez pas appeler self.filter() { ... } avec une fermeture qui attend la éléments devant être Idable.

À partir de Swift 2/Xcode 7 beta 2, vous pouvez définir des méthodes d'extension sur un type générique qui sont plus restrictives sur le modèle (comparer extension de tableau pour supprimer l'objet par valeur = pour un problème très similaire):

extension Array where Element : Idable {

    func filterWithId(id : String) -> [Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}

Alternativement, vous pouvez définir une méthode d'extension de protocole:

extension SequenceType where Generator.Element : Idable {

    func filterWithId(id : String) -> [Generator.Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}

filterWithId() est alors disponible pour tous les types conformes à SequenceType (en particulier à Array) si le type d'élément de séquence est conforme à Idable.

Dans Swift 3 ce serait

extension Sequence where Iterator.Element : Idable {

    func filterWithId(id : String) -> [Iterator.Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}
44
Martin R