Quando desejo verificar se um Bool opcional é verdadeiro, isso não funciona:
var boolean : Bool? = false
if boolean{
}
Isso resulta neste erro:
Tipo opcional '@IvalueBool?' não pode ser usado como booleano; teste para '! = nil' em vez disso
Não quero verificar se há zero; Quero verificar se o valor retornado é verdadeiro.
Sempre preciso fazer isso if boolean == true
se estiver trabalhando com um Bool opcional?
Visto que os opcionais não estão BooleanType
mais em conformidade com o , o compilador não deveria saber que eu quero verificar o valor do Bool?
Respostas:
Com booleanos opcionais, é necessário tornar a verificação explícita:
if boolean == true { ... }
Caso contrário, você pode desembrulhar o opcional:
if boolean! { ... }
Mas isso gera uma exceção de tempo de execução se booleano for
nil
- para evitar que:if boolean != nil && boolean! { ... }
Antes do beta 5 era possível, mas foi alterado conforme relatado nas notas de lançamento:
Adendo: conforme sugerido por @MartinR, uma variação mais compacta para a 3ª opção é usar o operador de coalescência:
if boolean ?? false { // this code runs only if boolean == true }
o que significa: se booleano não for nulo, a expressão avalia o valor booleano (ou seja, usando o valor booleano não agrupado), caso contrário, a expressão avalia para
false
fonte
if let
também funcionaria.if boolean ?? false { ... }
.if !(boolean ?? true) { ... }
:(Ligação opcional
Swift 3 e 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)'") }
O código
let booleanValue = booleanValue
retornafalse
sebooleanValue
fornil
e oif
bloco não executa. SebooleanValue
não fornil
, este código define uma nova variável chamadabooleanValue
de tipoBool
(em vez de opcional,Bool?
).O código Swift 3 e 4
booleanValue
(e código Swift 2.2where booleanValue
) avalia a novabooleanValue: Bool
variável. Se for verdade, oif
bloco é executado com abooleanValue: Bool
variável recém-definida no escopo (permitindo a opção de referenciar o valor vinculado novamente dentro doif
bloco).Nota: É uma convenção do Swift nomear a constante / variável associada da mesma forma que a constante / variável opcional, como
let booleanValue = booleanValue
. Essa técnica é chamada de sombreamento variável . Você pode quebrar as convenções e usar algo assimlet unwrappedBooleanValue = booleanValue, unwrappedBooleanValue
. Eu aponto isso para ajudar a entender o que está acontecendo. Eu recomendo usar sombreamento variável.Outras Abordagens
Nil coalescendo
A coalescência nula é clara para este caso específico
var booleanValue : Bool? = false if booleanValue ?? false { // executes when booleanValue is true print("optional booleanValue: '\(booleanValue)'") }
Verificar
false
não é tão clarovar booleanValue : Bool? = false if !(booleanValue ?? false) { // executes when booleanValue is false print("optional booleanValue: '\(booleanValue)'") }
Nota:
if !booleanValue ?? false
não compila.Forçar desembrulhar opcional (evitar)
Forçar o desempacotamento aumenta a chance de que alguém faça uma alteração no futuro que compila, mas falha durante a execução. Portanto, eu evitaria algo assim:
var booleanValue : Bool? = false if booleanValue != nil && booleanValue! { // executes when booleanValue is true print("optional booleanValue: '\(booleanValue)'") }
Uma abordagem geral
Embora esta questão de estouro de pilha pergunte especificamente como verificar se a
Bool?
estátrue
dentro de umaif
instrução, é útil identificar uma abordagem geral, seja verificando verdadeiro, falso ou combinando o valor não encapsulado com outras expressões.À medida que a expressão fica mais complicada, acho a abordagem de vinculação opcional mais flexível e fácil de entender do que outras abordagens. Nota que as obras de ligação opcionais com qualquer tipo opcional (
Int?
,String?
, etc.).fonte
if let
?while array.last < threshold { array.removeLast() }
if, let, where
usando este:while let last = array.last where last < threshold { array.removeLast() }
no Swift 2 ouwhile let last = array.last, last < threshold { array.removeLast() }
no 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") }
fonte
Encontrei outra solução, sobrecarregando os operadores booleanos. Por exemplo:
public func < <T: Comparable> (left: T?, right: T) -> Bool { if let left = left { return left < right } return false }
Isso pode não estar totalmente no "espírito" das mudanças de linguagem, mas permite o desempacotamento seguro de opcionais e pode ser usado para condicionais em qualquer lugar, incluindo loops while.
fonte
A resposta que achei mais fácil de ler é definir uma função. Não é muito complicado, mas faz o trabalho.
func isTrue(_ bool: Bool?) -> Bool { guard let b = bool else { return false } return b }
uso:
let b: Bool? = true if isTrue(b) { // b exists and is true } else { // b does either not exist or is false }
fonte
Como disse o Antonio
Passei algumas horas tentando entender uma linha de código que encontrei, mas essa discussão me colocou no caminho certo.
Esta citação é de agosto 2014 , e desde então a Apple introduziu
Never
seguinte proposta SE-0102 e este último tornou conformidade com Equatable, Hashable, erro e comparáveisAgora é possível verificar se um booleano está
nil
usandoNever?
:var boolean: Bool? = false boolean is Never? // false boolean = true boolean is Never? // false boolean = nil boolean is Never? // true
Na verdade, você pode usar qualquer outro tipo inabitável :
public enum NeverEver { } var boolean: Bool? = false boolean is NeverEver? // false boolean = true boolean is NeverEver? // false boolean = nil boolean is NeverEver? // true
Dito isso, também é possível usar um wrapper de propriedade agora:
@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"
ou mesmo:
@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"
fonte