Last active
September 24, 2022 18:01
-
-
Save ruslangazizov/b742f4bcd7f3bf8b7feed01c076e1408 to your computer and use it in GitHub Desktop.
Custom implementation of swift's Optional enum
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| enum CustomOptional<Wrapped> { | |
| case none | |
| case some(Wrapped) | |
| public init(_ some: Wrapped) { | |
| self = .some(some) | |
| } | |
| func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> CustomOptional<U> { | |
| switch self { | |
| case .none: | |
| return .none | |
| case .some(let wrapped): | |
| do { | |
| let transformed = try transform(wrapped) | |
| return .some(transformed) | |
| } catch let error { | |
| throw error | |
| } | |
| } | |
| } | |
| func flatMap<U>(_ transform: (Wrapped) throws -> CustomOptional<U>) rethrows -> CustomOptional<U> { | |
| switch self { | |
| case .none: | |
| return .none | |
| case .some(let wrapped): | |
| do { | |
| let transformed = try transform(wrapped) | |
| return transformed | |
| } catch let error { | |
| throw error | |
| } | |
| } | |
| } | |
| } | |
| extension CustomOptional: ExpressibleByNilLiteral { | |
| public init(nilLiteral: ()) { | |
| self = .none | |
| } | |
| } | |
| extension CustomOptional: CustomStringConvertible { | |
| public var description: String { | |
| switch self { | |
| case .none: | |
| return "nil" | |
| case .some(let wrapped): | |
| var wrappedDescription: String = "\(wrapped)" | |
| if wrapped is String { | |
| wrappedDescription = "\"\(wrappedDescription)\"" | |
| } | |
| return "CustomOptional(\(wrappedDescription))" | |
| } | |
| } | |
| } | |
| extension CustomOptional { | |
| static func ?? (lhs: Self, rhs: Self) -> Self { | |
| switch (lhs, rhs) { | |
| case (.none, .none): | |
| return .none | |
| case (.some(let value), _): | |
| return .some(value) | |
| case (.none, .some(let value)): | |
| return .some(value) | |
| } | |
| } | |
| static func ?? (lhs: Self, rhs: Wrapped) -> Wrapped { | |
| switch lhs { | |
| case .none: | |
| return rhs | |
| case .some(let value): | |
| return value | |
| } | |
| } | |
| } | |
| extension CustomOptional: Equatable where Wrapped: Equatable { | |
| static func == (lhs: Self, rhs: @autoclosure () -> Wrapped) -> Bool { | |
| switch lhs { | |
| case .none: | |
| return false | |
| case .some(let value): | |
| return value == rhs() | |
| } | |
| } | |
| static func == (lhs: @autoclosure () -> Wrapped, rhs: Self) -> Bool { | |
| return rhs == lhs() | |
| } | |
| } | |
| extension String { | |
| func toInt() -> CustomOptional<Int> { | |
| if let number = Int(self) { | |
| return .some(number) | |
| } else { | |
| return .none | |
| } | |
| } | |
| } | |
| let someInteger = CustomOptional(1) | |
| print(someInteger) // CustomOptional(1) | |
| let stringNumber = someInteger.map { "\($0)" } | |
| print(stringNumber) // CustomOptional("1") | |
| print(stringNumber.map { $0.toInt() }) // CustomOptional(CustomOptional(1)) | |
| print(stringNumber.flatMap { $0.toInt() }) // CustomOptional(1) | |
| let optionalInt: CustomOptional<Int> = nil | |
| let anotherOptionalInt = CustomOptional(9) | |
| let unwrappedInt = optionalInt ?? anotherOptionalInt ?? 5 | |
| print(optionalInt == anotherOptionalInt) // false | |
| print(optionalInt == unwrappedInt) // false | |
| print(unwrappedInt == optionalInt) // false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment