Cuando quiero verificar si un bool opcional es verdadero, hacer esto no funciona:
var boolean : Bool? = false
if boolean{
}
Resulta en este error:
Tipo opcional '@IvalueBool?' no se puede utilizar como booleano; prueba para '! = nil' en su lugar
No quiero comprobar nada; Quiero comprobar si el valor devuelto es verdadero.
¿Tengo que hacerlo siempre if boolean == true
si estoy trabajando con un bool opcional?
Dado que los opcionales ya no se ajustan BooleanType
, ¿no debería saber el compilador que quiero verificar el valor de Bool?
Respuestas:
Con booleanos opcionales, es necesario hacer la verificación explícita:
if boolean == true { ... }
De lo contrario, puede desenvolver el opcional:
if boolean! { ... }
Pero eso genera una excepción de tiempo de ejecución si boolean es
nil
, para evitar eso:if boolean != nil && boolean! { ... }
Antes de la beta 5 era posible, pero se ha cambiado como se informa en las notas de la versión:
Anexo: como lo sugiere @MartinR, una variación más compacta de la tercera opción es usar el operador coalescente:
if boolean ?? false { // this code runs only if boolean == true }
lo que significa: si booleano no es nil, la expresión se evalúa como el valor booleano (es decir, utilizando el valor booleano no envuelto); de lo contrario, la expresión se evalúa como
false
fuente
if let
también funcionaría.if boolean ?? false { ... }
.if !(boolean ?? true) { ... }
:(Enlace opcional
Swift 3 y 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)'") }
El código
let booleanValue = booleanValue
devuelvefalse
sibooleanValue
esnil
y elif
bloque no se ejecuta. SibooleanValue
no es asínil
, este código define una nueva variable denominadabooleanValue
de tipoBool
(en lugar de opcionalBool?
).El código Swift 3 y 4
booleanValue
(y el código Swift 2.2where booleanValue
) evalúa la nuevabooleanValue: Bool
variable. Si es cierto, elif
bloque se ejecuta con labooleanValue: Bool
variable recién definida en el alcance (lo que permite que la opción haga referencia al valor enlazado nuevamente dentro delif
bloque).Nota: Es una convención de Swift nombrar la constante / variable ligada de la misma manera que la constante / variable opcional como
let booleanValue = booleanValue
. Esta técnica se denomina sombreado variable . Podrías romper con las convenciones y usar algo comolet unwrappedBooleanValue = booleanValue, unwrappedBooleanValue
. Señalo esto para ayudar a comprender lo que está sucediendo. Recomiendo usar sombreado variable.Otros enfoques
Nil coalescencia
La fusión nula es clara para este caso específico
var booleanValue : Bool? = false if booleanValue ?? false { // executes when booleanValue is true print("optional booleanValue: '\(booleanValue)'") }
La comprobación
false
no es tan claravar booleanValue : Bool? = false if !(booleanValue ?? false) { // executes when booleanValue is false print("optional booleanValue: '\(booleanValue)'") }
Nota:
if !booleanValue ?? false
no se compila.Forzar desenvolver opcional (evitar)
Forzar el desenvolvimiento aumenta la posibilidad de que alguien haga un cambio en el futuro que compila pero falla en tiempo de ejecución. Por lo tanto, evitaría algo como esto:
var booleanValue : Bool? = false if booleanValue != nil && booleanValue! { // executes when booleanValue is true print("optional booleanValue: '\(booleanValue)'") }
Un enfoque general
Aunque esta pregunta de desbordamiento de pila pregunta específicamente cómo verificar si a
Bool?
estátrue
dentro de unaif
declaración, es útil identificar un enfoque general, ya sea verificar verdadero, falso o combinar el valor sin envolver con otras expresiones.A medida que la expresión se vuelve más complicada, encuentro que el enfoque de enlace opcional es más flexible y más fácil de entender que otros enfoques. Tenga en cuenta que las obras de enlace opcionales con cualquier tipo opcional (
Int?
,String?
, etc.).fuente
if let
?while array.last < threshold { array.removeLast() }
if, let, where
usando esto:while let last = array.last where last < threshold { array.removeLast() }
en Swift 2 owhile let last = array.last, last < threshold { array.removeLast() }
en 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") }
fuente
Encontré otra solución, sobrecargando los operadores booleanos. Por ejemplo:
public func < <T: Comparable> (left: T?, right: T) -> Bool { if let left = left { return left < right } return false }
Esto puede no estar totalmente en el "espíritu" de los cambios de lenguaje, pero permite desenvolver de forma segura los opcionales y se puede utilizar para los condicionales en cualquier lugar, incluidos los bucles while.
fuente
La respuesta que encontré más fácil de leer es definir una función. No es muy complicado, pero funciona.
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 }
fuente
Como dijo Antonio
Pasé algunas horas tratando de entender una línea de código con la que me topé, pero este hilo me puso en el camino correcto.
Esta cita es de agosto de 2014 y, desde entonces, Apple presentó la
Never
siguiente propuesta SE-0102 y la hizo cumplir con Equatable, Hashable, Error y Comparable.Ahora es posible verificar si un booleano está
nil
usandoNever?
:var boolean: Bool? = false boolean is Never? // false boolean = true boolean is Never? // false boolean = nil boolean is Never? // true
De hecho, puede usar cualquier otro tipo inhabitable :
public enum NeverEver { } var boolean: Bool? = false boolean is NeverEver? // false boolean = true boolean is NeverEver? // false boolean = nil boolean is NeverEver? // true
Dicho esto, también es posible usar un contenedor de propiedades ahora:
@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"
o incluso:
@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"
fuente