Проверка значения дополнительного Bool

Когда я хочу проверить, является ли опциональный Bool истинным, выполнение этого не работает:

var boolean : Bool? = false
if boolean{
}

Это приводит к ошибке:

Дополнительный тип '@IvalueBool?' не может использоваться как логическое; тест для '!= nil' вместо

Я не хочу проверять нуль; Я хочу проверить, вернётся ли значение.

Должен ли я всегда делать if boolean == true, если я работаю с дополнительным Bool?

Так как опции не соответствуют BooleanType, не должен ли компилятор знать, что я хочу проверить значение Bool?

Ответ 1

С дополнительными логическими значениями необходимо сделать чек явным:

if boolean == true {
    ...
}

В противном случае вы можете распаковать опцию:

if boolean! {
    ...
}

Но это генерирует исключение во время выполнения, если boolean nil - для предотвращения этого:

if boolean != nil && boolean! {
    ...
}

До бета-версии 5 это было возможно, но оно было изменено, как указано в примечаниях к выпуску:

Опционы уже неявно оценивают значение true, когда они имеют значение и false, когда они этого не делают, во избежание путаницы при работе с дополнительными значениями Bool. Вместо этого сделайте явную проверку против nil с операторами == или! =, Чтобы узнать, содержит ли опциональное значение значение.

Приложение: как предложено @MartinR, более компактным вариантом третьего варианта является использование оператора коалесценции:

if boolean ?? false {
    ...
}

что означает: если boolean не равен nil, выражение оценивается по логическому значению (т.е. с использованием развернутого логического значения), в противном случае выражение оценивается как false

Ответ 2

Дополнительная привязка

Swift 3 и 4

var booleanValue : Bool? = false
if let booleanValue = booleanValue, booleanValue {
    // Executes when booleanValue is not nil and true
    // A new constant "booleanValue: Bool" is defined and set
    print("bound booleanValue: '\(booleanValue)'")
}

Swift 2.2

var booleanValue : Bool? = false
if let booleanValue = booleanValue where booleanValue {
    // Executes when booleanValue is not nil and true
    // A new constant "booleanValue: Bool" is defined and set
    print("bound booleanValue: '\(booleanValue)'")
}

Код let booleanValue = booleanValue возвращает false, если booleanValue is nil и блок if не выполняется. Если booleanValue не nil, этот код определяет новую переменную с именем booleanValue типа Bool (вместо необязательной, Bool?).

Код Swift 3 и 4 booleanValue (и код Swift 2.2 where booleanValue) оценивает новую переменную booleanValue: Bool. Если это правда, блок if выполняется с помощью новой переменной booleanValue: Bool в области видимости (позволяющей опции ссылаться на связанное значение снова в блоке if).

Примечание. Это соглашение Swift для обозначения связанной константы/переменной так же, как и необязательная константа/переменная, например let booleanValue = booleanValue. Этот метод называется переменным затенением. Вы можете отказаться от соглашения и использовать что-то вроде let unwrappedBooleanValue = booleanValue, unwrappedBooleanValue. Я указываю это, чтобы понять, что происходит. Я рекомендую использовать переменную затенение.

 

Другие подходы

Ниль-коалесцирующий

Ниль-коалесцирование ясно для этого конкретного случая

var booleanValue : Bool? = false
if booleanValue ?? false {
    // executes when booleanValue is true
    print("optional booleanValue: '\(booleanValue)'")
}

Проверка на false не такая прозрачная

var booleanValue : Bool? = false
if !(booleanValue ?? false) {
    // executes when booleanValue is false
    print("optional booleanValue: '\(booleanValue)'")
}

Примечание: if !booleanValue ?? false не компилируется.

 

Принудительное форматирование необязательно (избегать)

Принудительное развертывание увеличивает вероятность того, что кто-то внесет изменения в будущее, которое компилируется, но сбой во время выполнения. Поэтому я бы избегал чего-то вроде этого:

var booleanValue : Bool? = false
if booleanValue != nil && booleanValue! {
    // executes when booleanValue is true
    print("optional booleanValue: '\(booleanValue)'")
}

 

Общий подход

Хотя этот вопрос задает вопрос, как проверить, является ли Bool? true в инструкции if, полезно определить общий подход, проверяя ли true, false или объединяете разворачиваемое значение с другими выражениями.

По мере того, как выражение становится более сложным, я нахожу дополнительный способ привязки более гибким и понятным, чем другие подходы. Обратите внимание, что необязательное связывание работает с любым необязательным типом (Int?, String? и т.д.).

Ответ 3

Я нашел другое решение, перегружая булевы операторы. Например:

public func < <T: Comparable> (left: T?, right: T) -> Bool {
    if let left = left {
        return left < right
    }
    return false
}

Это может быть не полностью в "духе" изменений языка, но оно позволяет безопасно разворачивать дополнительные опции и может использоваться для условий в любом месте, в том числе в циклах.