web-dev-qa-db-fra.com

Extension générique pour tableau en Swift

Pour être très franc, je suis totalement nouveau pour apprendre la création et l'utilisation d'extensions.

Je voulais créer une catégorie (Extension en Swift 3.0) qui peut être utilisée dans une application pour effectuer des opérations répétées pour Array.

Exemple de lien 1

C'est ce que j'ai vu et compris en faisant des recherches, je voulais créer une extension avec différentes méthodes qui devraient être génériques, et non sur la base du type de données nécessaire pour créer des extensions distinctes.

Ici, dans l'exemple ci-dessus, nous devrons créer une seule extension si nous optons pour une extension particulière du type de données. Je voulais avoir un guide s'il existe un moyen de créer la catégorie générique (Extension dans Swift).

  1. extension _ArrayType where Generator.Element == Int
  2. extension Array where Element: Equatable
  3. extension Array where Element == Int
  4. extension _ArrayType where Generator.Element == Float
  5. extension SequenceType where Self.Generator.Element: FloatingPointType
  6. extension Array where Element: DoubleValue
  7. extension Sequence where Iterator.Element == String

,etc...

Exemple de lien 2

Remarque: En bref, nous pouvons considérer que je veux effectuer des actions basées sur Array dans une seule extension au lieu de simplement créer l'extension unique pour chacun des types de données conformément à l'exigence ci-dessus.

14
Jignesh Fadadu

Comme mentionné dans les commentaires, une façon d'y parvenir est de créer votre propre protocole que les types que vous souhaitez couvrir adoptent (dans les commentaires quelqu'un l'a appelé Content, utilisé ci-dessous pour cet exemple) (à partir de première source ):

protocol Content {
    var hash: String { get }
}
extension Array where Element : Content {

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

Il semble, cependant, que la question d'origine concerne principalement les extensions génériques pour les tableaux, qui, selon un commentaire, ne sont pas possibles mais 100% sont possibles en Swift (c'est un gros Swift, en fait) (de deuxième source ).

Par exemple, si vous souhaitez définir une méthode d'extension spécifique pour Ints uniquement, vous pouvez le faire:

extension Sequence where Iterator.Element == Int {
    var sum: Int {
        return reduce(0, +)
    }
}

Il semble que les exigences initiales de la question soient des méthodes d'extension qui pourraient être indépendantes du type de données et devraient donc être gardées en commun. Si je comprends bien, il semble cependant que ces types de données ont en général une certaine conformité à Equatable et/ou Hashable, qui est l'exigence minimale pour que ce type de générique fonctionne. Cependant, avec la conformité de cet élément, cela est possible en tant que tel:

extension Sequence where Iterator.Element is Equatable {
    func extensionMethodName<T: Equatable>(_ input: [T], singleElement: T) -> [T] {
        // T is now a generic array of equatable items. You can implement whatever extension logic you need with these. 
        // I added different ways of passing in and returning this generic type, but the only thing that is likely going to be consistent is the `<T: Equatable>` which is Swift standard syntax for declaring generic type parameters for a method.
    }
}

La syntaxe Swift change rapidement, et ce qui est ici peut rapidement devenir obsolète, mais ce guide est maintenu assez à jour par Apple et montre la syntaxe la plus récente pour Generics utilisée ci-dessus ^.

Ma réponse provient d'un couple StackOverflow questions/réponses, utilisé par exemple/syntaxe ci-dessus ^. Source: (SO Source)(SO Source 2)

En résumé, toutes les méthodes ci-dessus peuvent être combinées, pour une solution d'extension entièrement personnalisée qui a à la fois des fonctions/vars génériques pour tous vos types Array, tout en ayant des remplacements d'extension spécifiques au type.

12
BHendricks

Dans la clause where, vous spécifiez "Si le type d'élément a ces règles, considérez cette extension".

Vous n'avez pas besoin d'implémenter toutes les méthodes dans toutes les extensions.

Par exemple:

  • Vous voulez étendre Array<Element> Pour avoir généralement la méthode foo(_:Element):

    extension Array {
        func foo(bar: Element) { /*your code goes here */ }
    }
    
  • Vous souhaitez étendre Array<Element> Là où Element a implémenté Equatable (qui inclut Int, Double et ... ou toute structure/classe que vous avez marquée comme Equatable):

    extension Array where Element: Equatable {
        func find(value: Element) -> Bool { 
            return index(of: value) != nil
        }
    }
    
  • Vous voulez étendre Sequence dans les cas où Element est Numeric, avoir une somme de variable get-only:

    extension Sequence where Element: Numeric {
        var sum: Element { 
            return reduce(0, +)
        }
    }
    
  • Vous souhaitez étendre Collection<Collection<Element: Equatable>> Pour avoir une méthode à comparer aux collections 2D:

    extension Collection
        where Iterator.Element: Collection, 
        Iterator.Element.Iterator.Element: Equatable {
    
        func compare(to: Self) -> Bool {
            let flattenSelf = self.reduce([], +)
            let flattenTo = to.reduce([], +)
    
            return flattenSelf.count == flattenTo.count &&
                Zip(flattenSelf, flattenTo).reduce(true) { $0 && $1.0 == $1.1 }
        }
    }
    

Vous n'avez pas besoin d'étendre Array ou collection pour avoir des méthodes comme sort, find, etc ... La plupart de ces méthodes sont déjà étendues à l'intérieur du compilateur si votre Element: Equatable ou Element: Comparable. en utilisant map, filter et reduce vous pouvez obtenir des structures plus complexes avec peu de code.

10
farzadshbfn