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

Идиома для работы с опциями в 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 не был константой.

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

val myValue = optionalValue.getOrElse(defaultValue)

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


person Wes Campaigne    schedule 07.06.2014    source источник


Ответы (5)


Обновить

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.

Примечание. Я запустил модуль, чтобы добавить в Swift такие общие помощники, как этот or на Optional.

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

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

result = myOptional ?? "n/a"
person MirekE    schedule 07.08.2014

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

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

person UnRewa    schedule 31.03.2016

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

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

Если вы пытаетесь сделать это с помощью String, вы можете сделать это ..

string1 = string2.isEmpty ? "Default Value":string2
person Plasma    schedule 08.02.2021