web-dev-qa-db-fra.com

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

L'idiome utilisé pour traiter les options dans Swift semble excessivement détaillé, si vous souhaitez simplement fournir une valeur par défaut dans le cas où il s'agirait de rien:

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

qui implique la duplication inutile de code, ou

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

qui nécessite unwrappedValue ne pas être une constante.

La monade Option de Scala (qui est fondamentalement la même idée que celle de Swift, optionnelle) utilise la méthode getOrElse à cette fin:

val myValue = optionalValue.getOrElse(defaultValue)

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

128
Wes Campaigne

Mettre à jour

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

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 méthode or

Remarque : J'ai lancé un module pour ajouter des aides communes comme ceci or sur Optional à Swift .

265
drewag

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

result = myOptional ?? "n/a"
27
MirekE

si vous avez écrit:

let result = optionalValue ?? 50

et optionalValue != nil puis result sera aussi optional et vous devrez le dérouler à l'avenir

Mais vous pouvez écrire 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 != nil alors result sera unwraped

3
UnRewa

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, la nécessité de lancer value as T est un vilain piratage. Idéalement, il devrait exister un moyen d'affirmer que T est identique au type contenu dans Optional. En l'état actuel, les ensembles d'inférence de types T sont basés sur le paramètre donné à getOrElse, puis échouent au moment de l'exécution si cela ne correspond pas à Facultatif et si Facultatif est non nul.

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
2
Wes Campaigne