if nil != optional ... 和 if let _ = optional ... 之间有什么区别?

What's the difference between if nil != optional … and if let _ = optional …

我需要测试 returns 可选的表达式是否为 nil。这看起来很简单,但这是代码。

if nil != self?.checklists.itemPassingTest({ [=10=] === note.object }) {
    …
}

出于某种原因,这在我看来很不愉快。

if let item = self?.checklists.itemPassingTest({ [=11=] === note.object }) {
    …
}

对我来说看起来好多了,但我实际上并不需要该物品,我只需要知道是否有退货。所以,我使用了以下内容。

if let _ = self?.checklists.itemPassingTest({ [=12=] === note.object }) {
    …
}

我是不是漏掉了什么微妙的东西?我认为 if nil != optional …if let _ = optional … 在这里是等价的。


更新以解决答案中的一些问题

  1. 我没看出nil != varvar != nil的区别,虽然我一般用var != nil。在这种情况下,在块获得与 if.

  2. 的布尔比较混合的块的布尔比较之后推送 != nil
  3. Wildcard Pattern 的使用应该不足为奇或不常见。它们用于元组 (x, _) = (10, 20)、for-in 循环 for _ in 1...5、case 语句 case (_, 0): 等(注意:这些示例取自 Swift 编程语言)。

这个问题是关于两种形式的功能等效性,而不是关于编码风格的选择。该对话可以在 programmers.stackexchange.com.

上进行

经过这么长时间,Swift 2.0 变得毫无意义

if self?.checklists.contains({ [=13=] === note.object }) ?? false {
    …
}

我个人认为这看起来很不愉快,因为您将 nil 与您的结果进行比较,而不是将您的结果与 nil 进行比较:

if self?.checklists.itemPassingTest({ [=10=] === note.object }) != nil {
    …
}

因为你只想确保它不是 nil 而不是使用 item 所以使用 let.

没有意义

if let 语法称为可选绑定。它接受一个可选项作为输入,如果可选项不为零,它会返回一个必需的常量。这适用于您首先检查值是否为 nil 的通用代码模式,如果它不是 nil(如果它有值),则对其进行处理。

如果可选的 nil,处理停止并跳过大括号内的代码。

if optional != nil 语法更简单。它只是检查可选值是否为 nil。它会跳过为您创建所需的常量。

如果您不打算使用结果值,可选的绑定语法会造成浪费和混淆。在这种情况下使用更简单的 if optional != nil 版本。正如 nhgrif 指出的那样,它生成的代码更少,而且您的意图更加清晰。

编辑:

听起来编译器足够聪明,如果您编写“if let”可选绑定代码但最终没有使用您绑定的变量,它不会生成额外的代码。主要区别在于可读性。使用可选绑定会产生您将使用绑定的可选对象的期望。

经过优化,这两种方式大概是一样的

例如,在这种情况下,使用 swiftc -O -emit-assembly if_let.swift 编译以下两个:

import Darwin

// using arc4random ensures -O doesn’t just
// ignore your if statement completely
let i: Int? = arc4random()%2 == 0 ? 2 : nil

if i != nil {
  println("set!")
}

import Darwin

let i: Int? = arc4random()%2 == 0 ? 2 : nil

if let _ = i {
  println("set!")
}

生成相同的汇编代码:

    ; call to arc4random
    callq   _arc4random
    ; check if LSB == 1 
    testb   , %al
    ; if it is, skip the println
    je  LBB0_1
    movq    [=12=], __Tv6if_let1iGSqSi_(%rip)
    movb    , __Tv6if_let1iGSqSi_+8(%rip)
    jmp LBB0_3
LBB0_1:
    movq    , __Tv6if_let1iGSqSi_(%rip)
    movb    [=12=], __Tv6if_let1iGSqSi_+8(%rip)
    leaq    L___unnamed_1(%rip), %rax  ; address of "set!" literal
    movq    %rax, -40(%rbp)
    movq    , -32(%rbp)
    movq    [=12=], -24(%rbp)
    movq    __TMdSS@GOTPCREL(%rip), %rsi
    addq    , %rsi
    leaq    -40(%rbp), %rdi
    ; call println
    callq   __TFSs7printlnU__FQ_T_
LBB0_3:
    xorl    %eax, %eax
    addq    , %rsp
    popq    %rbx
    popq    %r14
    popq    %rbp
    retq

AirspeedVelocity 的答案告诉我们 let _ =!= nil 生成相同的汇编代码,因此我强烈建议使用第一种方法。

事实上,如果你有类似的东西:

if let _ = optional {
    do_something()
}

...你想添加一些代码,现在你需要那个可选的,这个改变会更容易和更快:

if let wrapped = optional {
    do_something()
    do_something_else(with: wrapped)
}

使用let _ =并编写可维护的代码。