Когда я хочу проверить, истинно ли значение Optional Bool, это не сработает:
var boolean : Bool? = false
if boolean{
}
Это приводит к этой ошибке:
Необязательный тип @IvalueBool? не может использоваться как логическое; вместо этого проверьте '! = nil'
Я не хочу проверять ноль; Я хочу проверить, истинно ли возвращаемое значение.
Всегда ли я должен это делать, if boolean == true
если я работаю с Optional Bool?
Поскольку Optionals больше не соответствуют BooleanType
, не должен ли компилятор знать, что я хочу проверить значение Bool?
Ответы:
С необязательными логическими значениями необходимо сделать проверку явной:
if boolean == true { ... }
В противном случае вы можете развернуть необязательный:
if boolean! { ... }
Но это генерирует исключение времени выполнения, если логическое значение равно
nil
- чтобы предотвратить это:if boolean != nil && boolean! { ... }
До бета 5 это было возможно, но было изменено, как сообщается в примечаниях к выпуску:
Добавление: как предлагает @MartinR, более компактный вариант третьего варианта использует оператор объединения:
if boolean ?? false { // this code runs only if boolean == true }
что означает: если логическое значение не равно нулю, выражение оценивается как логическое значение (т.е. с использованием развернутого логического значения), в противном случае выражение оценивается как
false
источник
if let
также будет работать.if boolean ?? false { ... }
.if !(boolean ?? true) { ... }
:(Дополнительная привязка
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
есть,nil
иif
блок не выполняется. ЕслиbooleanValue
нетnil
, этот код определяет новую переменную с именемbooleanValue
типаBool
(вместо необязательного,Bool?
).Код Swift 3 и 4
booleanValue
(и код Swift 2.2where 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)'") }
Общий подход
Хотя этот вопрос о переполнении стека конкретно спрашивает, как проверить, находится ли a
Bool?
вtrue
пределахif
заявления, полезно определить общий подход ли проверка на истинный, ложный или комбинируя развернутое значение с другими выражениями.По мере усложнения выражения я считаю необязательный подход связывания более гибким и легким для понимания, чем другие подходы. Обратите внимание, что дополнительная привязка работает с любым дополнительным типом (
Int?
,String?
и т. Д.).источник
if let
?while array.last < threshold { array.removeLast() }
if, let, where
помощью этого:while let last = array.last where last < threshold { array.removeLast() }
в Swift 2 илиwhile let last = array.last, last < threshold { array.removeLast() }
в Swift 3.while let
.var enabled: Bool? = true if let enabled = enabled, enabled == true { print("when is defined and true at the same moment") } if enabled ?? false { print("when is defined and true at the same moment") } if enabled == .some(true) { print("when is defined and true at the same moment") } if enabled == (true) { print("when is defined and true at the same moment") } if case .some(true) = enabled { print("when is defined and true at the same moment") } if enabled == .some(false) { print("when is defined and false at the same moment") } if enabled == (false) { print("when is defined and false at the same moment") } if enabled == .none { print("when is not defined") } if enabled == nil { print("when is not defined") }
источник
Я нашел другое решение, перегрузив логические операторы. Например:
public func < <T: Comparable> (left: T?, right: T) -> Bool { if let left = left { return left < right } return false }
Возможно, это не полностью соответствует «духу» языковых изменений, но позволяет безопасно разворачивать опциональные элементы и может использоваться для условных выражений где угодно, включая циклы while.
источник
Ответ, который я нашел наиболее легким для чтения, - это определение функции. Не очень сложно, но работает.
func isTrue(_ bool: Bool?) -> Bool { guard let b = bool else { return false } return b }
Применение:
let b: Bool? = true if isTrue(b) { // b exists and is true } else { // b does either not exist or is false }
источник
Как сказал Антонио
Я потратил несколько часов, пытаясь понять строку кода, на которую наткнулся, но эта ветка направила меня на правильный путь.
Это цитата из августа 2014 года , и с тех пор Apple представила
Never
следующее предложение SE-0102, и последнее сделало его совместимым с Equatable, Hashable, Error и Comparable.Теперь можно проверить , если булева это с
nil
помощьюNever?
:var boolean: Bool? = false boolean is Never? // false boolean = true boolean is Never? // false boolean = nil boolean is Never? // true
Фактически вы можете использовать любые другие непригодные для проживания типы:
public enum NeverEver { } var boolean: Bool? = false boolean is NeverEver? // false boolean = true boolean is NeverEver? // false boolean = nil boolean is NeverEver? // true
При этом теперь также можно использовать оболочку свойств :
@propertyWrapper struct OptionalBool { public var wrappedValue: Bool? public var projectedValue: Bool { wrappedValue ?? false } public init(wrappedValue: Bool?) { self.wrappedValue = wrappedValue } } struct Struct { @OptionalBool var predicate: Bool? var description: String { if $predicate { return "predicate is true" } return "predicate is false" } } var object = Struct() object.description // "predicate is false" object.predicate = false object.description // "predicate is false" object.predicate = true object.description // "predicate is true"
или даже:
@propertyWrapper struct OptionalBool { var wrappedValue: Bool? var projectedValue: OptionalBool { self } var isNil: Bool { wrappedValue is Never? } var value: Bool { wrappedValue ?? false } init(wrappedValue: Bool?) { self.wrappedValue = wrappedValue } } struct Struct { @OptionalBool var predicate: Bool? var description: String { if $predicate.value { return "predicate is true" } if !$predicate.isNil { return "predicate is false" } return "predicate is nil" } } var object = Struct() object.description // "predicate is nil" object.predicate = false object.description // "predicate is false" object.predicate = true object.description // "predicate is true"
источник