Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

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

I need to test if an expression which returns an optional is nil. This seems like a no-brainer, but here is the code.

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

Which, for some reason, looks unpleasant to my eye.

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

Looks much better to me, but I don't actually need the item, I just need to know if one was returned. So, I used the following.

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

Am I missing something subtle here? I think if nil != optional … and if let _ = optional … are equivalent here.


Update to address some concerns in the answers

  1. I don't see the difference between nil != var and var != nil, although I generally use var != nil. In this case, pushing the != nil after the block gets the boolean compare of block mixed in with the boolean compare of the if.

  2. The use of the Wildcard Pattern should not be all that surprising or uncommon. They are used in tuples (x, _) = (10, 20), for-in loops for _ in 1...5, case statements case (_, 0):, and more (NOTE: these examples were taken from The Swift Programming Language).

This question is about the functional equivalency of the two forms, not about coding style choices. That conversation can be had on programmers.stackexchange.com.


After all this time, Swift 2.0 makes it moot

if self?.checklists.contains({ $0 === note.object }) ?? false {
    …
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

After optimization, the two approaches are probably the same.

For example, in this case, compiling both the following with 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!")
}

produces identical assembly code:

    ; 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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...