Какая разница между if nil!= Optional... и if let _ = 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 …
здесь эквивалентны.
Обновить для устранения некоторых проблем в ответах
-
Я не вижу разницы между nil != var
и var != nil
, хотя обычно использую var != nil
. В этом случае нажатие != nil
после блока получает логическое сравнение блока, смешанного с булевым сравнением if.
-
Использование шаблона подстановок не должно быть таким неожиданным или необычным. Они используются в кортежах (x, _) = (10, 20)
, for-in loops for _ in 1...5
, case case case (_, 0):
и т.д. (ПРИМЕЧАНИЕ: эти примеры взяты из языка Swift Programming).
Этот вопрос касается функциональной эквивалентности двух форм, а не выбора стиля кодирования. Этот разговор может быть сделан на programers.stackexchange.com.
После всего этого времени Swift 2.0 делает его спорным
if self?.checklists.contains({ $0 === note.object }) ?? false {
…
}
Ответы
Ответ 1
После оптимизации оба подхода, вероятно, одинаковы.
Например, в этом случае с помощью 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 $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 [email protected](%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
Ответ 2
Синтаксис if let
называется необязательным связыванием. Он принимает необязательный вход и возвращает требуемую константу, если необязательный параметр не равен нулю. Это предназначено для шаблона общего кода, в котором вы сначала проверяете, имеет ли значение значение nil, а если нет, вы что-то делаете с ним.
Если необязательный - nil, обработка останавливается и код внутри фигурных скобок пропускается.
Синтаксис if optional != nil
проще. Он просто проверяет, не является ли опциональным значение nil. Он пропускает создание необходимой константы для вас.
Необязательный синтаксис связывания является расточительным и запутанным, если вы не собираетесь использовать полученное значение. Используйте более простой вариант if optional != nil
в этом случае. Как указывает nhgrif, он генерирует меньше кода, плюс ваши намерения гораздо яснее.
EDIT:
Похоже, что компилятор достаточно умен, чтобы не генерировать дополнительный код, если вы пишете необязательный код привязки, если не хотите, но не используете переменную, которую вы связываете. Основное различие в читаемости. Использование необязательной привязки создает ожидание того, что вы собираетесь использовать необязательный, который вы связываете.
Ответ 3
Я лично считаю, что это выглядит неприятно, потому что вы сравниваете нуль с вашим результатом, а не своим результатом, с нолем:
if self?.checklists.itemPassingTest({ $0 === note.object }) != nil {
…
}
Поскольку вы только хотите убедиться, что это не нуль, а не использовать item
, нет смысла использовать let
.
Ответ 4
Ответ AirspeedVelocity показывает нам, что let _ =
и != nil
создают один и тот же код сборки, поэтому я настоятельно рекомендую использовать первый подход.
На самом деле, если у вас есть что-то вроде:
if let _ = optional {
do_something()
}
... и вы хотите добавить какой-то код, и теперь вам нужно это необязательно, это изменение будет проще и быстрее:
if let wrapped = optional {
do_something()
do_something_else(with: wrapped)
}
Используйте let _ =
и напишите код поддерживаемого кода.