Kiedy chcę sprawdzić, czy opcjonalna wartość logiczna jest prawdziwa, wykonanie tego nie działa:
var boolean : Bool? = false
if boolean{
}
Powoduje to ten błąd:
Opcjonalny typ „@IvalueBool?” nie może być używany jako wartość logiczna; zamiast tego przetestuj '! = nil'
Nie chcę sprawdzać, czy jest zero; Chcę sprawdzić, czy zwrócona wartość jest prawdziwa.
Czy zawsze muszę to robić, if boolean == true
jeśli pracuję z opcjonalnym boolem?
Skoro opcje nie są BooleanType
już zgodne z , czy kompilator nie powinien wiedzieć, że chcę sprawdzić wartość Bool?
Odpowiedzi:
W przypadku opcjonalnych wartości logicznych konieczne jest, aby czek był jawny:
if boolean == true { ... }
W przeciwnym razie możesz rozpakować opcjonalne:
if boolean! { ... }
Ale to generuje wyjątek czasu wykonywania, jeśli wartość logiczna jest
nil
- aby temu zapobiec:if boolean != nil && boolean! { ... }
Przed wersją beta 5 było to możliwe, ale zostało zmienione zgodnie z informacją o wydaniu:
Dodatek: zgodnie z sugestią @MartinR, bardziej zwarta odmiana trzeciej opcji wykorzystuje operator koalescencji:
if boolean ?? false { // this code runs only if boolean == true }
co oznacza: jeśli wartość logiczna nie jest równa nil, wynikiem wyrażenia jest wartość logiczna (tj. przy użyciu nieopakowanej wartości logicznej), w przeciwnym razie wynikiem wyrażenia jest
false
źródło
if let
też by działało.if boolean ?? false { ... }
.if !(boolean ?? true) { ... }
:(Opcjonalne wiązanie
Swift 3 i 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)'") }
Kod
let booleanValue = booleanValue
zwracafalse
ifbooleanValue
jest,nil
aif
blok nie jest wykonywany. JeślibooleanValue
nienil
, ten kod definiuje nową zmienną o nazwiebooleanValue
typeBool
(zamiast opcjonalnejBool?
).Kod Swift 3 i 4
booleanValue
(oraz kod Swift 2.2where booleanValue
) ocenia nowąbooleanValue: Bool
zmienną. Jeśli to prawda,if
blok jest wykonywany z nowo zdefiniowanąbooleanValue: Bool
zmienną w zakresie (umożliwiając opcję ponownego odniesienia do wartości związanej wif
bloku).Uwaga: Konwencją języka Swift jest nazwanie powiązanej stałej / zmiennej tak samo, jak opcjonalnej stałej / zmiennej, takiej jak
let booleanValue = booleanValue
. Ta technika nazywa się zmiennym cieniowaniem . Możesz zerwać z konwencją i użyć czegoś w rodzajulet unwrappedBooleanValue = booleanValue, unwrappedBooleanValue
. Wskazuję na to, aby pomóc zrozumieć, co się dzieje. Polecam używanie zmiennego cieniowania.Inne podejścia
Brak koalescencji
W tym konkretnym przypadku wyraźna jest koalescencja zerowa
var booleanValue : Bool? = false if booleanValue ?? false { // executes when booleanValue is true print("optional booleanValue: '\(booleanValue)'") }
Sprawdzanie dla
false
nie jest tak jasnevar booleanValue : Bool? = false if !(booleanValue ?? false) { // executes when booleanValue is false print("optional booleanValue: '\(booleanValue)'") }
Uwaga:
if !booleanValue ?? false
nie kompiluje się.Wymuś rozpakowywanie opcjonalne (unikaj)
Wymuszanie rozpakowywania zwiększa szansę, że ktoś w przyszłości dokona zmiany, która kompiluje się, ale ulega awarii w czasie wykonywania. Dlatego unikałbym czegoś takiego:
var booleanValue : Bool? = false if booleanValue != nil && booleanValue! { // executes when booleanValue is true print("optional booleanValue: '\(booleanValue)'") }
Podejście ogólne
Chociaż to pytanie o przepełnienie stosu pyta konkretnie, jak sprawdzić, czy a
Bool?
znajduje siętrue
wif
instrukcji, pomocne jest określenie ogólnego podejścia, czy sprawdzanie wartości prawda, fałsz czy łączenie nieopakowanej wartości z innymi wyrażeniami.Ponieważ wyrażenie staje się bardziej skomplikowane, uważam, że opcjonalne podejście wiążące jest bardziej elastyczne i łatwiejsze do zrozumienia niż inne podejścia. Należy zauważyć, że ewentualne prace związaniu z dowolnego typu (opcjonalnie
Int?
,String?
itp).źródło
if let
?while array.last < threshold { array.removeLast() }
if, let, where
używając tego:while let last = array.last where last < threshold { array.removeLast() }
w Swift 2 lubwhile 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") }
źródło
Znalazłem inne rozwiązanie, przeciążające operatory boolowskie. Na przykład:
public func < <T: Comparable> (left: T?, right: T) -> Bool { if let left = left { return left < right } return false }
Może to nie być całkowicie zgodne z „duchem” zmian językowych, ale pozwala na bezpieczne rozpakowywanie opcji i jest możliwe do użycia w przypadku warunków warunkowych w dowolnym miejscu, w tym w pętlach while.
źródło
Najłatwiejszą do odczytania odpowiedzią jest zdefiniowanie funkcji. Niezbyt skomplikowane, ale działa.
func isTrue(_ bool: Bool?) -> Bool { guard let b = bool else { return false } return b }
stosowanie:
let b: Bool? = true if isTrue(b) { // b exists and is true } else { // b does either not exist or is false }
źródło
Jak powiedział Antonio
Spędziłem kilka godzin próbując zrozumieć wiersz kodu, na który się natknąłem, ale ten wątek postawił mnie na właściwej drodze.
Ten cytat pochodzi z sierpnia 2014 r. , A od tego czasu Apple przedstawił
Never
następującą propozycję SE-0102, a następnie dostosował ją do Equatable, Hashable, Error i ComparableTeraz można sprawdzić, czy boolean
nil
używaNever?
:var boolean: Bool? = false boolean is Never? // false boolean = true boolean is Never? // false boolean = nil boolean is Never? // true
W rzeczywistości możesz użyć innych typów nienadających się do zamieszkania :
public enum NeverEver { } var boolean: Bool? = false boolean is NeverEver? // false boolean = true boolean is NeverEver? // false boolean = nil boolean is NeverEver? // true
Biorąc to pod uwagę, można teraz również użyć opakowania właściwości :
@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"
lub nawet:
@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"
źródło