检查Optional Bool的值

时间:2014-08-27 09:18:24

标签: swift boolean optional

当我想检查一个Optional Bool是否为true时,执行此操作不起作用:

var boolean : Bool? = false
if boolean{
}

导致此错误:

  

可选类型'@IvalueBool?'不能用作布尔值;测试'!= nil'   代替

我不想检查零;我想检查返回的值是否为真。

如果我正在使用Optional Bool,我是否总是必须if boolean == true

由于Optionals不再符合BooleanType,编译器是否应该知道我想检查Bool的值?

6 个答案:

答案 0 :(得分:167)

使用可选的布尔值,需要明确检查:

if boolean == true {
    ...
}

否则你可以解开可选的:

if boolean! {
    ...
}

但如果布尔值为nil,则会产生运行时异常 - 以防止:

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

在测试版5之前,它是可能的,但它已根据发行说明中的​​报告进行了更改:

  

Optionals在有值时不再隐式评估为true,否则不再隐式评估为false,以避免在使用可选的Bool值时出现混淆。相反,使用==或!=运算符对nil进行显式检查,以确定可选项是否包含值。

附录:正如@MartinR所建议的,第三种选择的更紧凑变体是使用合并算子:

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

表示:如果boolean不是nil,则表达式求值为布尔值(即使用展开的布尔值),否则表达式求值为false

答案 1 :(得分:37)

可选绑定

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 = booleanValuefalse并且booleanValue块未执行,则代码nil会返回if。如果booleanValue不是nil,则此代码定义一个名为booleanValue的{​​{1}}类型的新变量(而不是可选的Bool)。

Swift 3& 4代码Bool?(和Swift 2.2代码booleanValue)评估新的where booleanValue变量。如果为true,则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)'") } 语句中检查Bool?是否为true,但确定检查true,false或组合的一般方法是有帮助的用其他表达式解开的值。

随着表达式变得更加复杂,我发现可选绑定方法比其他方法更灵活,更易于理解。请注意,可选绑定适用于任何可选类型(ifInt?等)。

答案 2 :(得分:2)

android {
    buildTypes {
        release {
            // Enables code shrinking, obfuscation, and optimization for only
            // your project's release build type.
            minifyEnabled true

            // Enables resource shrinking, which is performed by the
            // Android Gradle plugin.
            shrinkResources true

            // Includes the default ProGuard rules files that are packaged with
            // the Android Gradle plugin. To learn more, go to the section about
            // R8 configuration files.
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

答案 3 :(得分: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
}

答案 4 :(得分:0)

Antonio

当具有可选值时,它们不再隐式地评估为true,没有值时不再隐式评估为false,以避免在使用可选的Bool值时产生混淆。相反,请使用==或!=运算符对nil进行显式检查,以找出可选值是否包含值。

我花了几个小时试图理解我偶然发现的一行代码,但是这个线程使我走上了正轨。

此引文来自august 2014,此后,苹果公司在Never之后引入了proposal SE-0102,后者使之符合Equatable, Hashable, Error and 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

话虽如此,现在也可以使用property wrapper了:

@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"

答案 5 :(得分:-1)

我找到了另一个解决方案,重载了布尔运算符。例如:

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

这可能不完全符合语言变化的“精神”,但它允许安全地展开选项,并且它可用于任何地方的条件,包括while循环。