Fornire un valore predefinito per un facoltativo in Swift?


141

Il linguaggio per trattare con gli opzionali in Swift sembra eccessivamente dettagliato, se tutto ciò che vuoi fare è fornire un valore predefinito nel caso in cui sia nullo:

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

che comporta inutilmente la duplicazione del codice, o

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

che richiede di unwrappedValuenon essere una costante.

La monade di Scala's Option (che è sostanzialmente la stessa idea di Swift's Optional) ha il metodo getOrElseper questo scopo:

val myValue = optionalValue.getOrElse(defaultValue)

Mi sto perdendo qualcosa? Swift ha già un modo compatto di farlo? Oppure, in mancanza, è possibile definire getOrElseun'estensione per Opzionale?


Risposte:


289

Aggiornare

Apple ha ora aggiunto un operatore di coalescenza:

var unwrappedValue = optionalValue ?? defaultValue

L'operatore ternario è tuo amico in questo caso

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

Puoi anche fornire la tua estensione per l'enum facoltativo:

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

Quindi puoi semplicemente fare:

optionalValue.or(defaultValue)

Tuttavia, raccomando di attenersi all'operatore ternario poiché altri sviluppatori lo capiranno molto più rapidamente senza dover studiare il ormetodo

Nota : ho iniziato un modulo per aggiungere aiutanti comuni come questo orsu Optionaldi SWIFT.


il mio complier mi mostra che il tipo di unwrappedValueè ancora il tipo opzionale per questo caso in Swift 1.2: var unwrappedValue = optionalValue ? optionalValue! : defaultValue(xcode 6 beta 4). È cambiato?
Semplicemente il

2
Sbaglio nella mia versione. Sono al 6.4. Attenzione: ??il comportamento di inferenza del tipo predefinito è che restituisce un facoltativo, che non è quello che si desidera in genere. Puoi dichiarare la variabile come non opzionale e questo funziona bene.
Semplicemente il

29

A partire da agosto 2014 Swift ha un operatore di coalescenza (??) che lo consente. Ad esempio, per una stringa opzionale myOptional potresti scrivere:

result = myOptional ?? "n/a"

4

se hai scritto:

let result = optionalValue ?? 50

e optionalValue != nilpoi resultlo sarà optionalanche tu e dovrai scartarlo in futuro

Ma puoi scrivere operatore

infix operator ??? { associativity left precedence 140 }

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

Ora puoi:

 let result = optionalValue ??? 50

E quando sarà optionalValue != nilallora resultunwraped


3

Quanto segue sembra funzionare

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

tuttavia la necessità di lanciare value as Tè un brutto trucco. Idealmente, dovrebbe esserci un modo per affermare che Tè lo stesso del tipo contenuto nell'Opzionale. TAllo stato attuale, digitare i set di inferenza in base al parametro fornito a getOrElse e quindi non riesce in fase di esecuzione se questo non corrisponde a Opzionale e Opzionale è diverso da zero:

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

Non è necessario specificare Tper il metodo. Questo in realtà sovrascrive l'esistente Tda Opzionale. Puoi solo fare: func getOrElse(defaultValue: T) -> Tquindi T si riferisce al tipo di valore reale dell'opzionale e non devi digitare controllalo
drewag

Grazie! Ho dedotto esattamente questo dalla seconda metà della tua risposta. Esiste un modo per ispezionare la definizione di opzionale per sapere che il tipo generico è definito come Tin quello? (al di là del semplice presupposto basato sulla convenzione)
Wes Campaigne,

Se fai clic sui comandi Optionalall'interno di Xcode, vedrai che è definito comeenum Optional<T>
drewag

Oh eccellente Avrei dovuto indovinare. Le definizioni lì dentro saranno utili; ci sono molte cose che non sono ancora nella documentazione. Grazie ancora.
Wes Campaigne,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.