Fournir une valeur par défaut pour une option dans Swift?


141

L'idiome pour traiter les options dans Swift semble excessivement verbeux, si tout ce que vous voulez faire est de fournir une valeur par défaut dans le cas où elle est nulle:

if let value = optionalValue {
    // do something with 'value'
} else {
    // do the same thing with your default value
}

qui implique une duplication inutile du code, ou

var unwrappedValue
if let value = optionalValue {
    unwrappedValue = value
} else {
    unwrappedValue = defaultValue
}

ce qui unwrappedValuene nécessite pas d'être une constante.

La monade Option de Scala (qui est fondamentalement la même idée que celle de Swift) a la méthode getOrElseà cet effet:

val myValue = optionalValue.getOrElse(defaultValue)

Est-ce que je manque quelque chose? Swift a-t-il déjà un moyen compact de le faire? Ou, à défaut, est-il possible de définir getOrElsedans une extension pour Optionnel?


Réponses:


289

Mettre à jour

Apple a maintenant ajouté un opérateur de fusion:

var unwrappedValue = optionalValue ?? defaultValue

L'opérateur ternaire est votre ami dans ce cas

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

Vous pouvez également fournir votre propre extension pour l'énumération facultative:

extension Optional {
    func or(defaultValue: T) -> T {
        switch(self) {
            case .None:
                return defaultValue
            case .Some(let value):
                return value
        }
    }
}

Ensuite, vous pouvez simplement faire:

optionalValue.or(defaultValue)

Cependant, je recommande de s'en tenir à l'opérateur ternaire car les autres développeurs le comprendront beaucoup plus rapidement sans avoir à étudier la orméthode

Note : J'ai commencé un module de d'ajouter des aides communes comme celui - ci orsur Optionalla rapidité.


mon complicateur me montre que le type de unwrappedValueest toujours le type optionnel pour ce cas dans Swift 1.2: var unwrappedValue = optionalValue ? optionalValue! : defaultValue(xcode 6 beta 4). Cela a-t-il changé?
SimplGy

2
Je me trompe sur ma version. Je suis sur 6.4. Attention: ??le comportement d'inférence de type par défaut est qu'il renvoie une option, ce qui n'est généralement pas ce que vous voulez. Vous pouvez déclarer la variable comme non facultative et cela fonctionne bien.
SimplGy

29

Depuis août 2014, Swift a un opérateur de fusion (??) qui permet cela. Par exemple, pour une chaîne optionnelle myOptional, vous pouvez écrire:

result = myOptional ?? "n/a"

4

si vous avez écrit:

let result = optionalValue ?? 50

et optionalValue != nilpuis le resultsera optionalaussi et vous devrez le déballer à l'avenir

Mais vous pouvez écrire un opérateur

infix operator ??? { associativity left precedence 140 }

func ???<T>(optLeft:T?, right:T!) -> T!
{
    if let left = optLeft
    {
        return left
    }
    else { return right}
}

Maintenant vous pouvez:

 let result = optionalValue ??? 50

Et quand optionalValue != nilalors resultsera-t-ilunwraped


3

Ce qui suit semble fonctionner

extension Optional {
    func getOrElse<T>(defaultValue: T) -> T {
        if let value = self? {
            return value as T
        } else {
            return defaultValue
        }
    }
}

cependant, le besoin de lancer value as Test un horrible hack. Idéalement, il devrait y avoir un moyen d'affirmer qui Test le même que le type contenu dans la propriété facultative. Dans l'état actuel des choses, tapez des ensembles d'inférence Tbasés sur le paramètre donné à getOrElse, puis échoue à l'exécution si cela ne correspond pas à facultatif et que facultatif n'est pas nil:

let x: Int?

let y = x.getOrElse(1.414) // y inferred as Double, assigned 1.414

let a: Int? = 5

let b: Double = a.getOrElse(3.14) // Runtime failure casting 5 to Double

Vous n'avez pas besoin de spécifier Tla méthode. Cela remplace en fait l'existant Tde facultatif. Vous pouvez simplement faire: func getOrElse(defaultValue: T) -> Talors T fait référence au type de valeur réelle de l'option et vous n'avez pas à taper check it
dessiné le

Merci! C'est exactement ce que j'ai déduit de la seconde moitié de votre réponse. Existe-t-il un moyen d'inspecter la définition de Optional pour savoir que le type générique est défini comme Tdans celui-ci? (au-delà de la simple supposition basée sur la convention)
Wes Campaigne

Si vous command-cliquez sur à l' Optionalintérieur de Xcode, vous verrez qu'il est défini commeenum Optional<T>
drewag

Oh, excellent. J'aurais dû deviner. Les définitions qui y figurent seront utiles; il y a beaucoup de choses qui ne sont pas encore dans la documentation. Merci encore.
Wes Campaigne
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.