J'ai essayé d'extraire des valeurs non nulles du tableau Ssortingng. Comme ci-dessous. Mais mon aîné veut aussi pouvoir extraire des valeurs non nulles d'autres types.
J'ai lu, les generics pourraient m'aider à gérer différents types. Comment puis-je utiliser des generics pour que je puisse utiliser l'extension suivante pour travailler avec d'autres types?
getNonNil
doit renvoyer les valeurs non nulles extraites du type spécifique (ie si array est [Ssortingng?] il doit returnner [Ssortingng], returnne [Int] if [Int?] )
Parce que je dois faire d'autres calculs.
Ce que j'ai essayé est ci-dessous:
import Foundation // Extended the collection-type so that collectiontype is constrained to having element with optional ssortingngs extension CollectionType where Self.Generator.Element == Optional<Ssortingng>{ func getNonNil() -> [Ssortingng] { // filter out all nil elements and forcefully unwrap them using map return self.filter({$0 != nil}).map({$0!}) } } // Usage let x: [Ssortingng?] = ["Er", "Err", nil, "errr"] x.getNonNil().forEach { (str) in print(str) }
Il n'y a pas de moyen facile d'y parvenir grâce à une extension, car vous ne pouvez pas introduire de nouveaux types generics dans les extensions (bien que cela fasse partie du Manifeste Swift Generics – peut-être dans une future version de Swift).
Comme le dit @kennytm , la solution la plus simple consiste simplement à utiliser flatMap
, qui filter nil
:
x.flatMap{$0}.forEach { (str) in print(str) }
Si toutefois vous voulez toujours cela comme une extension, vous pouvez utiliser une solution de contournement de protocole afin de vous permettre de contraindre l'extension à tout type d'élément optionnel (Swift 3):
protocol _OptionalProtocol { associatedtype Wrapped func _asOptional() -> Wrapped? } extension Optional : _OptionalProtocol { func _asOptional() -> Wrapped? {return self} } extension Collection where Self.Iterator.Element : _OptionalProtocol { func getNonNil() -> [Iterator.Element.Wrapped] { return flatMap{$0._asOptional()} } } ... let x : [Ssortingng?] = ["Er", "Err", nil, "errr"] x.getNonNil().forEach { (str) in print(str) }
(Dans Swift 3, CollectionType
a été renommé en Collection
, et Generator
est maintenant Iterator
)
Bien que flatMap
soit presque certainement préféré dans cette situation, je ne fais que l'append pour l'amour de l'achèvement.
Pour getNonNil
vous pouvez simplement utiliser
x.flatMap { $0 } // returns ["Er", "Err", "errr"] which is [Ssortingng]
Pour la question d'origine, vous pouvez typiquement introduire un protocole au type optionnel (par exemple via le packageage muukii / OptionalProtocol ):
protocol OptionalProtocol { associatedtype Wrapped var value: Wrapped? { get } } extension Optional: OptionalProtocol { public var value: Wrapped? { return self } } extension CollectionType where Self.Generator.Element: OptionalProtocol { func getNonNil() -> [Self.Generator.Element.Wrapped] { ... } }
L'approche la plus simple consiste à utiliser flatMap
comme suggéré par kennytm , mais si vous voulez absolument savoir comment créer une telle méthode en utilisant des generics, une approche consisterait à créer une méthode globale qui prend en count la collection en tant que paramètre:
public func getNonNil<T, C: CollectionType where C.Generator.Element == Optional<T>>(collection: C) -> [T] { return collection.filter({$0 != nil}).map({$0!}) } let x: [Ssortingng?] = ["Er", "Err", nil, "errr"] print(getNonNil(x)) // returns ["Er", "Err", "errr"]