Как сравнивать опциональные значения (Optional) в Swift?

«Как сравнивать опциональные значения (Optional) в Swift?» — вопрос из категории Swift Core, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Опционалы в Swift сравниваются с помощью операторов == и !=. Сравнение происходит по значению, которое они хранят (или факту его отсутствия).

Основные правила:

  1. Два опционала равны (==), если они оба nil ИЛИ оба не-nil и их распакованные значения равны.
  2. Swift позволяет сравнивать опционал с неопционалом благодаря автоматической упаковке (optional wrapping).

Примеры:

let optionalA: Int? = 5
let optionalB: Int? = 5
let optionalC: Int? = 10
let optionalNil: Int? = nil

print(optionalA == optionalB) // true (оба 5)
print(optionalA == optionalC) // false (5 != 10)
print(optionalNil == nil)     // true (оба nil)
print(optionalA == nil)       // false (5 != nil)

// Сравнение опционала с неопционалом
let nonOptional: Int = 5
print(optionalA == nonOptional) // true (Optional(5) == 5)

Важные нюансы:

  • Типовая безопасность: Нельзя сравнивать опционалы разных типов (например, Int? и String?).
  • Сравнение ссылок (===): Оператор === проверяет, ссылаются ли две переменные на один и тот же экземпляр объекта в памяти. Он применим только к reference-типам (классам) и не сравнивает значения внутри опционалов.
    
    class MyClass {}
    let obj1 = MyClass()
    let refA: MyClass? = obj1
    let refB: MyClass? = obj1
    let refC: MyClass? = MyClass()

print(refA == refB) // true (== по умолчанию для классов сравнивает ссылки? Нет! Нужно реализовать Equatable) print(refA === refB) // true (одна и та же ссылка в памяти) print(refA === refC) // false (разные объекты в памяти)


Для пользовательских типов необходимо соответствие протоколу `Equatable`, чтобы работало сравнение `==`.