Opérateur personnalisé pour simplifier If-Let

Je voudrais simplifier le besoin constant de faire

if let firstName = firstName { self.name = firstName } 

Une coutume possible, un opérateur générique pour ce faire serait

 infix operator ?= {} func ?= <T>(inout left: T, right: T?) { if let right = right { left = right } } 

pour simplifier l'exemple précédent à

 self.name ?= firstName 

Cela crée un problème où si la valeur de firstName est nulle , alors Swift enveloppera la valeur dans un optionnel.

 var name: Ssortingng? = "Bob" var firstName: Ssortingng? = nil self.name ?= firstName print(self.name) /* prints "nil" since it is wrapping firstName in an optional when passed in. Eg Optional<nil> gets unwrapped to nil in function and assigned */ 

Une solution possible à l'opérateur personnalisé? J'ai essayé de limiter le paramètre de gauche à ne pas être optionnel mais cela n'est pas possible avec les contraintes de type generics.

Le problème (comme vous l'avez correctement identifié) est que parce que l'argument côté gauche est de type T , lorsque vous lui passez un caractère optionnel, T sera déduit comme Optional<Whatever> . Parce que l'argument du côté droit est T? (et parce que les types peuvent être librement promus en optionals), il en déduira que le type est Optional<Optional<Whatever>> , conduisant au double emballage confus que vous observez.

La solution consiste à append une surcharge pour gérer la situation lorsque l'argument de gauche est également facultatif.

 infix operator ?= {} func ?= <T>(inout left: T, right: T?) { if let right = right { left = right } } // overload to deal with an optional left handed side func ?= <T>(inout left: T?, right: T?) { if let right = right { left = right } } 

(Notez que dans Swift 3, inout devrait apparaître avant le type de paramètre)

Maintenant, si vous utilisez cet opérateur avec un argument optionnel comme gaucher, Swift utilisera la version surchargée au lieu de la version originale, car elle favorisera toujours la signature plus spécifique au type. Cela signifie que le côté droit ne sera pas enveloppé dans un double optionnel, car il est maintenant du même type que l'argument de gauche.

 var name: Ssortingng? = "Bob" var firstName: Ssortingng? = nil name ?= firstName print(name) // prints: Optional("Bob") 

Notez que c'est similaire à ce que le ?? a, il a deux définitions pour traiter un côté étant facultatif, un côté étant non-facultatif et les deux côtés étant facultatifs afin d'éviter la génération des optionnels enveloppés doubles:

 @warn_unused_result public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T @warn_unused_result public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T?) rethrows -> T? 

J'ai trouvé un moyen intéressant de réduire les frais généraux de if let par Nil Coalescing Operator

L'opérateur de coalescence nil (a ?? b) déballe un optionnel a s'il contient une valeur, ou returnne une valeur par défaut b si a est nul. L'expression a est toujours de type facultatif. L'expression b doit correspondre au type qui est stocké dans a.

En bref – nonOptional = optional ?? someDefaultValue nonOptional = optional ?? someDefaultValue
Par exemple –

 let defaultColorName = "red" var userDefinedColorName: Ssortingng? // optional variable var colorNameToUse = userDefinedColorName ?? defaultColorName 

Donc, ici si userDefinedColorName est nul alors defaultColorName sera asservi à la variable non-optionnelle colorNameToUse .
Pour une reference complète, consultez cette documentation Swift