如果有条件的话,令人惊讶的可选择解包

时间:2014-10-30 00:45:24

标签: swift

如果这是预期的行为,请试着绕过我的脑袋:

重构一些具有以下形式的代码:

let opt:Int? = 9

if let unwrapped = opt {
  if unwrapped > 5 {
    println("Yes")
    // Prints Yes
  }
}

我想删除嵌套的If语句。使用更紧凑的形式如此工作按预期工作:

if (opt ?? 0) > 5 {
  println("Yes")
  // Prints Yes
}

然而,我很惊讶与可选项的直接比较似乎也在条件中打开了可选项:

if opt > 5 {
  println("Yes")
  // Prints Yes
}

我用其他类型对此进行了测试,它们都具有相同的行为。显然,从Apple的文档中,检查了一个可选项是否等于nil,但是,我没想到它也会用包装的值进行评估。

我是否遗漏了某些内容(这是可以预料的)或者这是不受支持的选项行为?这似乎是将条件与选项组合起来的一种更简单的方法。

格雷格

1 个答案:

答案 0 :(得分:3)

> operator的一个定义是:

func ><T : _Comparable>(lhs: T?, rhs: T?) -> Bool

似乎编译器正在使用该版本的函数来比较Int?5。我们可以直接使用swiftc并要求它输出快速中间语言(SIL)来确认这一点:

swiftc -emit-silgen compare.swift

它输出半可读代码,如果我们深入研究它,我们可以看到它用于比较的函数调用:

// function_ref Swift.> infix <A : Swift._Comparable>(Swift.Optional<A>, Swift.Optional<A>) -> Swift.Bool
%17 = function_ref @_TFSsoi1gUSs11_Comparable__FTGSqQ__GSqQ___Sb : $@thin <τ_0_0 where τ_0_0 : _Comparable> (@in Optional<τ_0_0>, @in Optional<τ_0_0>) -> Bool // user: %28

这表明它确实使用>运算符的版本需要两个Optional

5不是Optional,那该怎么办?

好吧,如果我们更深入地了解SIL代码,我们可以看到如何。显然,Swift能够执行与可选绑定相反的操作,即将Optional注入一个非可选值:

// function_ref Swift._injectValueIntoOptional <A>(A) -> Swift.Optional<A>
%25 = function_ref @_TFSs24_injectValueIntoOptionalU__FQ_GSqQ__ : $@thin <τ_0_0> (@out Optional<τ_0_0>, @in τ_0_0) -> () // user: %26

所以看起来正在发生的事情是我们基本上最终做了类似于(但不完全相同)的事情:

let opt: Int? = 9
if opt > (5 as Int?) {
    println("Yes")
}

注意:即使我们执行以下操作,此功能仍然有效:

let opt: Int? = 9
let five: Int = 5
if opt > five {
   println("Yes")
}

它仍会将five注入Optional,以便它可以执行比较。