Можно ли реализовать кастомный аналог типа Optional в Swift?

Ответ

Да, можно создать свой тип, аналогичный Optional. Для этого используется enum с двумя случаями, как и у встроенного типа.

Базовая реализация:

enum MyOptional<Wrapped> {
    case some(Wrapped)
    case none

    // Аналог map для Optional
    func map<U>(_ transform: (Wrapped) -> U) -> MyOptional<U> {
        switch self {
        case .some(let value): 
            return .some(transform(value))
        case .none: 
            return .none
        }
    }

    // Аналог flatMap
    func flatMap<U>(_ transform: (Wrapped) -> MyOptional<U>) -> MyOptional<U> {
        switch self {
        case .some(let value): 
            return transform(value)
        case .none: 
            return .none
        }
    }
}

Особенности кастомной реализации:

  1. Generic-тип Wrapped позволяет хранить любое значение.
  2. Реализация основных методовmap, flatMap, filter.
  3. Синтаксический сахар можно добавить через расширения (например, инициализатор для неявного обертывания).
  4. Нет специальной поддержки компилятора — встроенный Optional имеет оптимизации и синтаксис (?, !), недоступные для пользовательских типов.

Пример использования:

let myValue: MyOptional<Int> = .some(10)
let squared = myValue.map { $0 * $0 } // .some(100)

let empty: MyOptional<Int> = .none
let result = empty.map { $0 * 2 } // .none

Ответ 18+ 🔞

Ага, ну вот, смотри, блядь, как это работает. Ты хочешь свой собственный Optional накодить, да? Ну типа, чтобы понимать, как эта штука изнутри устроена, а не просто ? и ! тыкать, как обезьяна.

Так вот, слушай сюда, ёпта. Всё до пизды просто, на самом деле. Берёшь обычный enum, да не простой, а дженерик, и делаешь в нём два кейса. Прям как в настоящем Optional, только своими кривыми ручками.

Базовая реализация, смотри не обосрись:

enum MyOptional<Wrapped> {
    case some(Wrapped) // Вот тут у нас значение лежит, завёрнутое, как кот в одеяло
    case none          // А тут нихуя. Пустота. Вакуум. Пиздец.

    // Аналог map для Optional. Это чтобы преобразовывать значение, если оно есть.
    func map<U>(_ transform: (Wrapped) -> U) -> MyOptional<U> {
        switch self {
        case .some(let value): 
            // О, есть чё-то! Превращаем его во что-то другое и заворачиваем обратно.
            return .some(transform(value))
        case .none: 
            // А тут нихуя нет, так что и возвращаем нихуя. Логично же, блядь.
            return .none
        }
    }

    // Аналог flatMap. Это когда твоё преобразование само возвращает опционал.
    func flatMap<U>(_ transform: (Wrapped) -> MyOptional<U>) -> MyOptional<U> {
        switch self {
        case .some(let value): 
            // Даём значение преобразованию, пусть сам разбирается, что возвращать.
            return transform(value)
        case .none: 
            // Опять нихуя. Скучно, предсказуемо, зато надёжно.
            return .none
        }
    }
}

А теперь, сука, особенности, чтобы ты не думал, что ты теперь бог опционалов:

  1. Дженерик Wrapped — это чтобы внутрь можно было запихнуть что угодно: Int, String, или даже другого ебаногомандюка.
  2. Методы map, flatMap — это основа основ. Без них твой опционал — просто мёртвая хуйня в коробочке.
  3. Синтаксический сахар типа неявного обертывания можно прикрутить через расширения, но это уже высший пилотаж, ёпта.
  4. А вот главный подвох, блядь! У встроенного Optional есть поддержка компилятора. У него есть эти волшебные ? и !, он умный, оптимизированный. А твой MyOptional — это просто твой enum. Никакого сахара, только хардкор. Зато понятно, как оно работает, да?

Ну и пример, чтобы окончательно врубиться:

let myValue: MyOptional<Int> = .some(10) // Завернули десятку
let squared = myValue.map { $0 * $0 }    // Развернули, возвели в квадрат, завернули обратно. Получится .some(100)

let empty: MyOptional<Int> = .none       // А тут пусто, блядь
let result = empty.map { $0 * 2 }        // Преобразовывать нечего, так что останется .none

Вот и вся магия, ёпта. Сделал свой велосипед. Теперь ты знаешь, что внутри у этой коробочки с вопросом. Главное — не пытайся теперь везде свой MyOptional пихать, а то будешь выглядеть как тот самый чувак, который на велосипеде на метро ездит.