Podanie wartości domyślnej opcjonalnego w języku Swift?

141

Idiom do radzenia sobie z opcjami w Swift wydaje się nadmiernie rozwlekły, jeśli wszystko, co chcesz zrobić, to podać wartość domyślną w przypadku, gdy jest zerowa:

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

co wiąże się z niepotrzebnym powielaniem kodu lub

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

która unwrappedValuenie wymaga stałej.

Monada Option Scali (która jest w zasadzie tym samym pomysłem co opcja Swift) ma metodę getOrElsedo tego celu:

val myValue = optionalValue.getOrElse(defaultValue)

Czy coś mi brakuje? Czy Swift ma już na to kompaktowy sposób? Lub, jeśli to nie wystarczy, czy można zdefiniować getOrElserozszerzenie dla Optional?

Wes Campaigne
źródło

Odpowiedzi:

289

Aktualizacja

Firma Apple dodała teraz operatora koalescencji:

var unwrappedValue = optionalValue ?? defaultValue

Operator trójskładnikowy jest w tym przypadku Twoim przyjacielem

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

Możesz także podać własne rozszerzenie opcjonalnego wyliczenia:

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

Następnie możesz po prostu zrobić:

optionalValue.or(defaultValue)

Zalecam jednak trzymać się operatora trójskładnikowego, ponieważ inni programiści zrozumieją to znacznie szybciej bez konieczności badania ormetody

Uwaga : Zacząłem moduł dodawania wspólne pomocników tak orna OptionalSWIFT.

drewag
źródło
mój współpracownik pokazuje mi, że typ unwrappedValuejest nadal opcjonalnym typem dla tego przypadku w Swift 1.2: var unwrappedValue = optionalValue ? optionalValue! : defaultValue(xcode 6 beta 4). Czy to się zmieniło?
SimplGy
2
Mylę się co do mojej wersji. Jestem na 6.4. Uważaj: ??domyślne zachowanie wnioskowania o typie polega na tym, że zwraca opcjonalne, co zwykle nie jest tym, czego chcesz. Możesz zadeklarować zmienną jako nieobowiązkową i to działa dobrze.
SimplGy
29

Od sierpnia 2014 r. Swift ma operatora koalescencji (??), który to umożliwia. Na przykład dla opcjonalnego String myOptional można napisać:

result = myOptional ?? "n/a"
MirekE
źródło
4

jeśli napisałeś:

let result = optionalValue ?? 50

a optionalValue != nilpotem też resultbędzie optionali będziesz musiał go rozpakować w przyszłości

Ale możesz napisać operator

infix operator ??? { associativity left precedence 140 }

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

Teraz możesz:

 let result = optionalValue ??? 50

A kiedy optionalValue != nilto resultbędzieunwraped

UnRewa
źródło
3

Następujące wydaje się działać

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

jednak potrzeba rzucania value as Tjest brzydka. W idealnym przypadku powinien istnieć sposób potwierdzenia, że Tjest taki sam, jak typ zawarty w pliku Optional. W obecnej postaci wpisz zestawy wnioskowania Tna podstawie parametru podanego w getOrElse, a następnie zakończy się niepowodzeniem w czasie wykonywania, jeśli nie jest to zgodne z wartością opcjonalną, a wartość opcjonalna jest różna od zera:

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
źródło
Nie musisz określać Tmetody. To faktycznie zastępuje istniejące Tz Optional. Możesz po prostu zrobić: func getOrElse(defaultValue: T) -> Twtedy T odnosi się do rzeczywistego typu wartości opcjonalnej i nie musisz wpisywać, sprawdź to
drewag
Dzięki! Dokładnie to wywnioskowałem z drugiej połowy twojej odpowiedzi. Czy jest jakiś sposób, aby sprawdzić definicję Opcjonalny, aby wiedzieć, że typ ogólny jest zdefiniowany Tw ten sposób? (poza prostym założeniem opartym na konwencji)
Wes Campaigne
Jeśli klikniesz polecenie Optionalwewnątrz Xcode, zobaczysz, że jest zdefiniowany jakoenum Optional<T>
drewag,
Och, świetnie. Powinienem się domyślić. Definicje tam zawarte będą przydatne; jest wiele rzeczy, których nie ma jeszcze w dokumentacji. Dzięki jeszcze raz.
Wes Campaigne