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

时间:2015-03-28 21:44:32

标签: swift optional

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

if nil != self?.checklists.itemPassingTest({ $0 === note.object }) {
    …
}

由于某些原因,我的眼睛看起来很不愉快。

if let item = self?.checklists.itemPassingTest({ $0 === note.object }) {
    …
}

对我来说看起来好多了,但我实际上并不需要这个项目,我只需要知道是否有人退回。所以,我使用了以下内容。

if let _ = self?.checklists.itemPassingTest({ $0 === note.object }) {
    …
}

我错过了一些微妙的东西吗?我认为if nil != optional …if let _ = optional …在这里是等效的。


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

  1. 虽然我通常使用nil != var,但我看不出var != nilvar != nil之间的区别。在这种情况下,在块之后推送!= nil得到混合的块的布尔比较与if的布尔比较。

  2. Wildcard Pattern的使用不应该令人惊讶或不常见。它们用于元组(x, _) = (10, 20),for-in循环for _ in 1...5,case语句case (_, 0):等等(注意:这些示例来自Swift编程语言)。

    < / LI>

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


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

    if self?.checklists.contains({ $0 === note.object }) ?? false {
        …
    }
    

4 个答案:

答案 0 :(得分:21)

优化后,这两种方法可能是相同的。

例如,在这种情况下,使用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!")
}

VS

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   $1, %al
    ; if it is, skip the println
    je  LBB0_1
    movq    $0, __Tv6if_let1iGSqSi_(%rip)
    movb    $1, __Tv6if_let1iGSqSi_+8(%rip)
    jmp LBB0_3
LBB0_1:
    movq    $2, __Tv6if_let1iGSqSi_(%rip)
    movb    $0, __Tv6if_let1iGSqSi_+8(%rip)
    leaq    L___unnamed_1(%rip), %rax  ; address of "set!" literal
    movq    %rax, -40(%rbp)
    movq    $4, -32(%rbp)
    movq    $0, -24(%rbp)
    movq    __TMdSS@GOTPCREL(%rip), %rsi
    addq    $8, %rsi
    leaq    -40(%rbp), %rdi
    ; call println
    callq   __TFSs7printlnU__FQ_T_
LBB0_3:
    xorl    %eax, %eax
    addq    $32, %rsp
    popq    %rbx
    popq    %r14
    popq    %rbp
    retq

答案 1 :(得分:15)

if let语法称为可选绑定。它需要一个可选的输入,如果optional不是nil,则返回一个必需的常量。这适用于您首先检查值是否为零的公共代码模式,如果不是,则使用它执行某些操作。

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

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

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

编辑:

听起来好像编译器非常聪明,如果你写了#34;就不会产生额外的代码。如果让&#34;可选的绑定代码,但不要使用绑定的变量。主要区别在于可读性。使用可选绑定会产生期望您将使用绑定的可选项。

答案 2 :(得分:5)

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

if self?.checklists.itemPassingTest({ $0 === note.object }) != nil {
    …
}

由于您只想确保它不是零并且不使用item,因此使用let毫无意义。

答案 3 :(得分:1)

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

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

if let _ = optional {
    do_something()
}

...而且您想要添加一些代码,现在您需要这个可选项,这种更改将更容易,更快捷:

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

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