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

Idiom do radzenia sobie z opcjami w języku Swift wydaje się nadmiernie gadatliwy, jeśli chcesz tylko podać domyślną wartość w przypadku, gdy jest zerowa:

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

, która polega na niepotrzebnym powielaniu kodu, lub

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

Który wymaga unwrappedValue nie być stałą.

Opcja Scali monad (która jest zasadniczo taka sama jak opcja Swifta) ma do tego celu metodę getOrElse:

val myValue = optionalValue.getOrElse(defaultValue)

Czy coś przeoczyłem? Czy Swift ma na to sposób już? Lub, w przeciwnym razie, czy możliwe jest zdefiniowanie getOrElse w rozszerzeniu dla opcjonalnego?

Author: Wes Campaigne, 2014-06-07

5 answers

Update

Apple dodało operatora koalescencyjnego:

var unwrappedValue = optionalValue ?? defaultValue

Operator trójdzielny jest twoim przyjacielem w tym przypadku

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

Możesz również podać własne rozszerzenie dla opcjonalnego enum:

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

Wtedy możesz po prostu zrobić:

optionalValue.or(defaultValue)

Zalecam jednak trzymanie się operatora trójdzielnego, ponieważ inni programiści zrozumieją to znacznie szybciej, bez konieczności badania metody or

Uwaga : zacząłem Moduł {[26] } aby dodać do Swifta popularne helpery jak ten or na Optional.

 224
Author: drewag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-11 06:12:07

Od sierpnia 2014 Swift ma operatora koalescencyjnego (??) na to pozwala. Na przykład, dla opcjonalnego ciągu myOptional można napisać:

result = myOptional ?? "n/a"
 23
Author: MirekE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-07 22:22:43

Jeśli napisałeś:

let result = optionalValue ?? 50

I optionalValue != nil wtedy result również będzie optional i będziesz musiał go rozpakować w przyszłości

Ale można 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 != nil wtedy result będzie unwraped

 3
Author: UnRewa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-31 08:38:22

Wygląda na to, że działa

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

Jednak potrzeba rzucania {[2] } to brzydki hack. W idealnej sytuacji powinien istnieć sposób na stwierdzenie, że T jest taki sam jak typ zawarty w fakultatywnym. W obecnej formie, typuj zestawy wnioskujące T na podstawie parametru podanego getOrElse, a następnie zawiedzie w czasie wykonywania, jeśli nie pasuje do opcjonalnego i opcjonalny jest inny niż 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
 1
Author: Wes Campaigne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-07 17:47:19

Zrobiłem prostą bibliotekę rozszerzeń i używałem jej do redukcji tak powtarzalnych kodów. Rzuca i zwraca Opcjonalne typy prymitywne do wartości domyślnej. Rzucasz jak poniżej,

CGFloat(optionalValue)

Lub z pewną wartością domyślną,

Int(optionalValue, defaultValue: 100)

Możesz przejrzeć to repozytorium.

 1
Author: DragonCherry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-15 02:27:30