Ответ
Да, можно создать свой тип, аналогичный 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
}
}
}
Особенности кастомной реализации:
- Generic-тип
Wrappedпозволяет хранить любое значение. - Реализация основных методов —
map,flatMap,filter. - Синтаксический сахар можно добавить через расширения (например, инициализатор для неявного обертывания).
- Нет специальной поддержки компилятора — встроенный
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
}
}
}
А теперь, сука, особенности, чтобы ты не думал, что ты теперь бог опционалов:
- Дженерик
Wrapped— это чтобы внутрь можно было запихнуть что угодно:Int,String, или даже другого ебаногомандюка. - Методы
map,flatMap— это основа основ. Без них твой опционал — просто мёртвая хуйня в коробочке. - Синтаксический сахар типа неявного обертывания можно прикрутить через расширения, но это уже высший пилотаж, ёпта.
- А вот главный подвох, блядь! У встроенного
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 пихать, а то будешь выглядеть как тот самый чувак, который на велосипеде на метро ездит.