Bereitstellen eines Standardwerts für eine Option in Swift?

141

Die Redewendung für den Umgang mit Optionen in Swift scheint übermäßig ausführlich zu sein, wenn Sie nur einen Standardwert für den Fall angeben möchten, dass er Null ist:

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

das beinhaltet unnötiges Duplizieren von Code, oder

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

was erfordert, unwrappedValuekeine Konstante zu sein.

Scalas Optionsmonade (die im Grunde die gleiche Idee wie Swifts Optional ist) hat die Methode getOrElsefür diesen Zweck:

val myValue = optionalValue.getOrElse(defaultValue)

Vermisse ich etwas Hat Swift schon eine kompakte Möglichkeit, das zu tun? Oder ist es andernfalls möglich, getOrElsein einer Erweiterung für Optional zu definieren ?

Wes Campaigne
quelle

Antworten:

289

Aktualisieren

Apple hat jetzt einen Koaleszenzoperator hinzugefügt:

var unwrappedValue = optionalValue ?? defaultValue

Der ternäre Operator ist in diesem Fall Ihr Freund

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

Sie können auch Ihre eigene Erweiterung für die optionale Aufzählung bereitstellen:

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

Dann können Sie einfach tun:

optionalValue.or(defaultValue)

Ich empfehle jedoch, sich an den ternären Operator zu halten, da andere Entwickler dies viel schneller verstehen, ohne die orMethode untersuchen zu müssen

Hinweis : Ich begann ein Modul hinzufügen gemeinsame Helfer wie diese orauf Optionalrasche zu.

Drawag
quelle
Mein Complier zeigt mir, dass der Typ unwrappedValuein Swift 1.2 immer noch der optionale Typ für diesen Fall ist: var unwrappedValue = optionalValue ? optionalValue! : defaultValue(xcode 6 beta 4). Hat sich das geändert?
SimplGy
2
Ich bin falsch in meiner Version. Ich bin am 6.4. Beachten Sie: Das ??Standardverhalten für Typinferenz ist, dass ein optionales zurückgegeben wird, was normalerweise nicht gewünscht wird. Sie können die Variable als nicht optional deklarieren, und dies funktioniert gut.
SimplGy
29

Seit August 2014 hat Swift einen Koaleszenzoperator (??), der dies ermöglicht. Für einen optionalen String myOptional könnten Sie beispielsweise schreiben:

result = myOptional ?? "n/a"
MirekE
quelle
4

wenn du geschrieben hast:

let result = optionalValue ?? 50

und optionalValue != nildann resultwird es optionalauch sein und Sie müssen es in Zukunft auspacken

Sie können aber Operator schreiben

infix operator ??? { associativity left precedence 140 }

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

Jetzt kannst du:

 let result = optionalValue ??? 50

Und wann wird es optionalValue != nildann resultseinunwraped

UnRewa
quelle
3

Das Folgende scheint zu funktionieren

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

Die Notwendigkeit zu werfen value as Tist jedoch ein hässlicher Hack. Im Idealfall sollte es eine Möglichkeit geben, zu behaupten, dass sie Tmit dem in der Option enthaltenen Typ identisch ist. TGeben Sie derzeit Inferenzsätze basierend auf dem für getOrElse angegebenen Parameter ein und schlagen Sie zur Laufzeit fehl, wenn dies nicht mit Optional übereinstimmt und Optional nicht Null ist:

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
Wes Campaigne
quelle
Sie müssen Tfür die Methode nichts angeben . Das überschreibt tatsächlich das vorhandene Tvon Optional. Sie können einfach tun: func getOrElse(defaultValue: T) -> Tdann bezieht sich T auf den realen
Werttyp
Vielen Dank! Genau das habe ich aus der zweiten Hälfte Ihrer Antwort abgeleitet. Gibt es eine Möglichkeit, die Definition von Optional zu überprüfen, um zu wissen, dass der generische Typ wie folgt definiert ist T? (über die bloße Annahme aufgrund der Konvention hinaus)
Wes Campaigne
Wenn Sie mit der Befehlstaste auf OptionalXcode klicken , sehen Sie, dass es definiert ist alsenum Optional<T>
drawag
Oh, ausgezeichnet. Ich hätte es erraten sollen. Die Definitionen dort werden nützlich sein; Es gibt viele Dinge, die noch nicht in der Dokumentation enthalten sind. Danke noch einmal.
Wes Campaigne