Предоставляете значение по умолчанию для Optional в Swift?

143

Идиома для работы с опциями в Swift кажется чрезмерно многословной, если все, что вы хотите сделать, это указать значение по умолчанию в случае, если оно равно нулю:

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

что включает в себя ненужное дублирование кода, или

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

который unwrappedValueне требует постоянного значения.

Монада Option в Scala (которая по сути совпадает с идеей необязательной в Swift) имеет getOrElseдля этой цели метод :

val myValue = optionalValue.getOrElse(defaultValue)

Я что-то упускаю? У Swift уже есть компактный способ сделать это? Или, в противном случае, можно ли определить getOrElseрасширение для Optional?

Уэс Кампейн
источник

Ответы:

293

Обновить

Apple добавила оператор объединения:

var unwrappedValue = optionalValue ?? defaultValue

Тернарный оператор в этом случае ваш друг

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

Вы также можете предоставить собственное расширение для необязательного перечисления:

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

Тогда вы можете просто сделать:

optionalValue.or(defaultValue)

Тем не менее, я рекомендую придерживаться тернарного оператора, так как другие разработчики поймут это гораздо быстрее, не исследуя orметод.

Примечание : Я начал модуль для добавления общих помощников , как это orна OptionalСвифт.

Дрюаг
источник
мой компилятор показывает мне, что тип по- unwrappedValueпрежнему является необязательным типом для этого случая в Swift 1.2: var unwrappedValue = optionalValue ? optionalValue! : defaultValue(xcode 6 beta 4). Это изменилось?
SimplGy
2
Я ошибаюсь в своей версии. Я на 6.4. Имейте в ??виду: поведение вывода типа по умолчанию заключается в том, что он возвращает необязательный параметр, что обычно не является тем, что вам нужно. Вы можете объявить переменную как необязательную, и это прекрасно работает.
SimplGy
29

По состоянию на август 2014 года в Swift есть оператор объединения (??), который позволяет это. Например, для необязательного String myOptional вы можете написать:

result = myOptional ?? "n/a"
MirekE
источник
4

если вы написали:

let result = optionalValue ?? 50

и optionalValue != nilтогда resultбудет optionalтоже, и вам нужно будет развернуть его в будущем

Но вы можете написать оператор

infix operator ??? { associativity left precedence 140 }

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

Теперь вы можете:

 let result = optionalValue ??? 50

И когда optionalValue != nilтогда resultбудетunwraped

UnRewa
источник
3

Кажется, работает следующее

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

однако необходимость в приведении value as T- уродливый прием. В идеале должен быть способ утверждения, который Tсовпадает с типом, содержащимся в Optional. В существующем виде введите наборы для выводаT основаны на параметре, заданном для getOrElse, а затем завершаются ошибкой во время выполнения, если это не соответствует необязательному, а параметр Optional не равен нулю:

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
Уэс Кампейн
источник
Указывать Tметод не нужно . Это фактически отменяет существующее Tиз Optional. Вы можете просто сделать: func getOrElse(defaultValue: T) -> Tтогда T относится к типу реального значения необязательного, и вам не нужно вводить его, проверьте его
drewag
Благодарность! Я сделал вывод из второй половины вашего ответа. Есть ли способ проверить определение Optional, чтобы узнать, что общий тип определен как Tв этом? (помимо простого предположения, основанного на соглашении)
Wes Campaigne
Если вы щелкните Optionalвнутри Xcode, enum Optional<T>
удерживая нажатой клавишу Command
Ой, отлично. Я должен был догадаться. Приведенные там определения будут полезны; есть много вещей, которых еще нет в документации. Еще раз спасибо.
Wes Campaigne