【问题标题】:The implicit unwrapping of an optional boolean可选布尔值的隐式展开
【发布时间】:2014-06-09 20:08:22
【问题描述】:

Bool 类型的隐式展开似乎不起作用:

var aBoolean: Bool!    // nil
aBoolean = false       // false
aBoolean               // false

aBoolean == true       // false
aBoolean == false      // true

if aBoolean {
    "Hum..."            // "Hum..."
} else {
    "Normal"
}

if aBoolean! {
    "Hum..."
} else {
    "Normal"          // "Normal"
}

如果我像 var aBoolean: Bool? 一样声明 aBoolean,这将是预期的行为,但在这里,我不明白。

这是正确的行为吗?我没有找到任何关于它的文档。

谢谢!

【问题讨论】:

  • 我很高兴有一天能输入if !bool! ...
  • ^ 我也是这么想的!哈
  • 该代码无法编译。你缺少一个花括号。

标签: swift


【解决方案1】:

第一个测试是检查 aBoolean 是否存储值而不是 nil,它确实:

if aBoolean {
    "Hum..."            // "Hum..."
else {
    "Normal"
}

第二个测试是检查存储在 aBoolean 中的实际布尔值,这是错误的:

if aBoolean! {
    "Hum..."
} else {
    "Normal"          // "Normal"
}

这在 Swift 书籍的“隐式包装的选项”部分中进行了说明。我认为隐式展开不适用于 if 语句。我同意这很奇怪,但这是苹果的例子:

您仍然可以将隐式展开的可选项视为普通可选项,以检查它是否包含值:

let assumedString: String! = "An implicitly unwrapped optional string."

if assumedString {
    println(assumedString)
}
// prints "An implicitly unwrapped optional string."

摘自:Apple Inc. “Swift 编程语言”。电子书。 https://itun.es/us/jEUH0.l

【讨论】:

  • 是的,但问题是如果布尔值通过使用感叹号声明为“隐式解包”,他为什么需要解包布尔值
  • @Dash 请看上面的评论
  • 这本书说:“您仍然可以将隐式展开的可选项视为普通可选项,以检查它是否包含值”,我认为这暗示了这种if 将检查值的存在,而不是检查值本身。
  • @MattGibson 谢谢!您可以在回复中添加来源,我会立即接受吗? :)
  • 感谢@MattGibson!我想我们在同一时间找到了报价:)
【解决方案2】:

不是一个答案,但如果这确实是隐式展开布尔值的预期行为,那将是相当令人不安的。只要您在任何逻辑命题中使用该表达式,它就会被展开:

var aBoolean: Bool! = false

if !aBoolean {
    "I'm unwrapping"            // "I'm unwrapping"
}

if aBoolean == false {
    "I'm unwrapping"            // "I'm unwrapping"
}

假设你的代码中有这个,并且在某个时候你的模型发生了变化并且条件被颠倒了,你删除了 NOT。

if aBoolean {
    "I'm unwrapping"            // <- ouch
}

你刚刚被搞砸了。让我想避免隐式展开。

【讨论】:

  • 通常你应该避免隐式展开。它的动机是像IBOutlets 这样的案例。这里有一个类,其成员变量在 init() 完成后仍为 nil,但在加载 nib 时被赋值。所以从awakeFromNib() 之前开始,它们永远不会有 nil 值,所有的展开都是毫无意义的。这些东西是可可对象而不是布尔值,因此您提出的问题不适用。使用隐式展开可能还有其他类似的情况。但对于一般用途,您应该使用普通条件。
  • 我并不认为隐式展开的正确应用是稀缺的。我要说的是,我认为一个更好的实现是让它表现为一个布尔值,除非你明确地尝试用“if let”解开它......
  • 不存在对 Bool 进行隐式展开的正确应用。你的建议会破坏 if 与任何其他隐式展开类型的使用,没有任何好处。
  • 查看stackoverflow.com/questions/24842834/… 的回复 Apple 认识到了这个问题。
【解决方案3】:

您正在进行两种不同的真实性检查。

给定:

var aBoolean: Bool!    // nil
aBoolean = false       // false

if aBoolean {
    "Hum..."            // "Hum..."
else {
    "Normal"
}

if aBoolean! {
    "Hum..."
} else {
    "Normal"          // "Normal"
}

...在第一个if aBoolean 中,该值没有被解包,它只是测试可选类型以确定它是否存储一个值。

在第二个if aBoolean! 中,您正在测试展开后的 Bool 的真值。

要查看它 确实被隐式解包(未在条件中使用时),请尝试:

println("value of implicitly-unwrapped aBoolean: \(aBoolean)")

...这将在 aBoolean 设置为 true 时打印 'true',在设置为 false 时打印'false',在尚未分配时打印'nil'。

【讨论】:

    【解决方案4】:

    以下是清楚显示的行为:

    > var bool1 : Bool!
    bool1: Bool! = nil
    > bool1 = false
    > (bool1 ? "yes" : "no")
    $R19: (String) = "yes"
    

    在上面,由于bool1 是一个可选(它变成一个Some 实例),简单bool1 的条件计算为true(它不是nil )。

    > var bool2 : Bool = false
    bool2: Bool = false
    > (bool2 ? "yes" : "no")
    $R25: (String) = "no"
    

    bool2 不是一个可选时,简单的bool2 的条件计算结果为falsebool2 的值)

    【讨论】:

      【解决方案5】:

      当声明一个变量为“隐式解包”时,使用!,它仍然是Optional

      这种类型的变量的行为与 Objective-C 中的标准变量类型非常相似。它可以分配给nil,但是当您访问成员时,您不需要显式解包它。这样,它就像在 ObjC 中一样“不安全”,因为您可以从 nil 访问属性

      因此,它在从 Objective-C 桥接时最常使用。但是,它仍然是可选的,唯一的区别是您不需要打开它来访问内容。

      我相信这主要是为了支持 Swift 和 Obj-C 之间的互操作,并且可能是在纯 Swift 代码中谨慎使用它的好习惯。 (Swift 指南现在是一个模糊的东西,很快就会有人证明我错了!)

      【讨论】:

      • 在纯粹的 Swift 中,它们对 IBOutlets 很有用。在加载 nib 之前,这些都是 nil ,但从那时起它们就有了值。每次检查该值将是乏味的。但是在这里它们被用于 Cocoa 对象,所以对于 Bool 来说很混乱!不是问题。
      • @SteveWaddicor 好点!我相信IBOutlets 默认情况下是隐式解包的选项,所以你真的不需要! 语法。
      猜你喜欢
      • 1970-01-01
      • 2017-01-30
      • 2016-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-26
      • 1970-01-01
      相关资源
      最近更新 更多