Optional Bool의 값 확인


88

Optional Bool이 true인지 확인하고 싶을 때이 작업이 작동하지 않습니다.

var boolean : Bool? = false
if boolean{
}

다음 오류가 발생합니다.

선택적 유형 '@IvalueBool?' 부울로 사용할 수 없습니다. 대신 '! = nil'테스트

nil을 확인하고 싶지 않습니다. 반환 된 값이 참인지 확인하고 싶습니다.

if boolean == trueOptional Bool로 작업하는 경우 항상해야 합니까?

Optionals가 BooleanType더 이상 준수하지 않기 때문에 컴파일러가 Bool의 값을 확인하고 싶다는 것을 알지 못합니까?


Booleans는 Equatable 프로토콜을 따르므로 선택 사항을 비 선택 사항과 비교할 수 있습니다. 여기를
Honey

답변:


192

선택적 부울을 사용하면 확인을 명시 적으로 만들어야합니다.

if boolean == true {
    ...
}

그렇지 않으면 선택 사항을 풀 수 있습니다.

if boolean! {
    ...
}

그러나 부울이 다음과 같은 경우 런타임 예외가 생성됩니다 nil.

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

베타 5 이전에는 가능했지만 릴리스 노트에보고 된대로 변경되었습니다.

선택적 Bool 값으로 작업 할 때 혼동을 피하기 위해 옵션은 더 이상 값이 있으면 true로, 그렇지 않으면 false로 암시 적으로 평가되지 않습니다. 대신 == 또는! = 연산자를 사용하여 nil에 대해 명시 적으로 검사하여 옵션에 값이 포함되어 있는지 확인하십시오.

부록 : @MartinR이 제안한대로 세 번째 옵션에 대한보다 간결한 변형은 병합 연산자를 사용하는 것입니다.

if boolean ?? false {
    // this code runs only if boolean == true
}

즉, 부울이 nil이 아니면 표현식이 부울 값으로 평가되고 (즉, 래핑되지 않은 부울 값 사용), 그렇지 않으면식이 다음과 같이 평가됩니다. false


4
세 번째 옵션은 코드의 의도를 표현하는 가장 좋은 방법이기 때문에 선호되는 솔루션입니다. 사용 if let도 작동합니다.
Sulthan 2014-08-27

29
"nil 통합 연산자 ??":를 사용하는 세 번째 옵션의 변형입니다 if boolean ?? false { ... }.
Martin R

4
그러나 내가 그것을 부정하고 싶다면 그것은 우스꽝스러워 보이기 시작한다. if !(boolean ?? true) { ... }:(
Andreas

2
최악의 아이디어를 강제로 풀었습니다. 항상 피해야합니다.
마티유 Riegler

4
첫 번째 옵션의 문제점은 무엇입니까? 나에게 그것은 최선의 방법 인 것 같습니다.
Vahid Amiri

43

선택적 바인딩

스위프트 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)'")
}

스위프트 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입니다 nilif블록이 실행되지 않습니다. 하면 booleanValue되지 nil,이 코드라는 새로운 변수 정의 booleanValue유형 Bool(대신, 선택의을 Bool?).

Swift 3 & 4 코드 booleanValue(및 Swift 2.2 코드 where booleanValue)는 새 booleanValue: Bool변수를 평가합니다 . 참이면 if블록은 booleanValue: Bool범위에서 새로 정의 된 변수로 실행됩니다 (옵션이 if블록 내에서 바인딩 된 값을 다시 참조하도록 허용 ).

참고 : 바인딩 된 상수 / 변수의 이름을 .NET과 같은 선택적 상수 / 변수와 동일하게 지정하는 것은 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?등).


선택적 for while 루프와 함께 부울 식을 사용하는 데 어려움이 있습니다. nil 병합 연산자는 작동하지만 지저분하고 오류가 발생하기 쉽습니다. 사용하는 방법이 if let있습니까?
jbaraga 16'16. 9.

@jbaraga, 궁금한 while 루프의 예를 게시하십시오.
Mobile Dan

배열을 스택으로 사용할 때 조건이 충족되거나 스택이 비어있을 때까지 값을 팝하고 싶습니다. 예 :while array.last < threshold { array.removeLast() }
jbaraga

다음을 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에서
Mobile Dan

고마워요. 나는 몰랐다 while let.
jbaraga

1
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")
}

0

부울 연산자를 오버로드하는 또 다른 해결책을 찾았습니다. 예를 들면 :

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

이것은 언어 변경의 "정신"에 완전히 포함되어 있지 않을 수 있지만 선택 사항의 안전한 언 래핑을 허용하며 while 루프를 포함한 모든 조건에서 사용할 수 있습니다.


1
죄송합니다. 원래 게시물을 돌아 보면 특정 질문에 대한 답변이 아니라 이전 댓글에서 제기 한 질문에 대한 답변이 아닙니다.
jbaraga

nil이 nil이 아닌 값보다 "큰"값으로 처리되는 것을 원하지 않는 경우가있을 수 있기 때문에이 오버로드를 사용하는 데 매우주의 할 것입니다 (특정 컨텍스트에서 반대의 결과를 원할 수 있습니다. 완전히 처리). 대신 일반 언 래핑을 사용하면 모든 경우에 nil을 처리하려는 방법을 명시 적으로 지정해야하므로 예기치 않은 결과가 발생할 가능성이 줄어 듭니다.
John Montgomery

0

가장 읽기 쉬운 답은 함수를 정의하는 것입니다. 별로 복잡하지는 않지만 일을합니다.

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
}

0

으로 안토니오는 말했다

선택적 Bool 값으로 작업 할 때 혼동을 피하기 위해 옵션은 더 이상 값이 있으면 true로, 그렇지 않으면 false로 암시 적으로 평가되지 않습니다. 대신 == 또는! = 연산자를 사용하여 nil에 대해 명시 적으로 검사하여 옵션에 값이 포함되어 있는지 확인하십시오.

나는 내가 우연히 발견 한 코드 줄을 이해하기 위해 몇 시간을 보냈지 만이 스레드는 나를 올바른 길로 인도했다.

이 인용에서이다 2014년 8월 애플이 소개 한 다음부터 Never다음과 같은 제안 SE-0102을 하고, 후자는 그것을 준수했다 Equatable, 해쉬, 오류 및 필적

이제 부울이 다음을 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"

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.