Swift 开发新高度:自己动手实现 Optional 类型

这里每天分享一个 iOS 的新知识,快来关注我吧

前言

对于熟悉 Swift 开发的同学一定对 Optional 类型不陌生,它是 Swift 中一个强大的特性,它通过显式处理有值或无值(nil)帮助我们编写更安全的代码。

Swift 提供了对 Optionals 的内置支持,今天来讲讲如何实现一个自定义的 Optionals 类型。

定义我们的自定义 Optional

首先我们来看看官方 Optional 这个类型的声明:

public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
}

这段代码声明在 Swift.Optional 中,可以看出一些信息:

  1. 它实际上是个枚举(enum)

  2. 它声明了一个泛型 Wrapped,做为 some 的关联值

  3. 它有两个 case,none 和 some

那么,我们按着官方的代码也使用 enum 来定义我们的自定义 Optional 类型:

enum CustomOptional<Wrapped> {
    case some(Wrapped)
    case none
}

这个枚举同样也有两个 case :some 包含一个关联值,表示包装的类型;none 表示值的缺失(nil)。泛型 <Wrapped> 允许我们的 CustomOptional 适用于任何类型。

访问和解包值

接下来,我们添加一些方法来访问和解包值:

extension CustomOptional {
    // MARK: - 访问和解包
    var value: Wrapped? {
        switch self {
        case .some(let wrapped): // 有值
            return wrapped
        case .none: // 无值
            return nil
        }
    }

    // 解包
    func unwrap() throws -> Wrapped {
        switch self {
        case .some(let wrapped): // 有值
            return wrapped
        case .none: // 无值
            // 抛出一个错误
            throw CustomOptionalError.unwrappingNone
        }
    }

    enum CustomOptionalError: Error {
        case unwrappingNone // 无值,无法解包
    }
}

简单解释一下这段代码,我们添加了一个 value 属性和一个 unwrap() 方法:

value 属性:返回包装的值,如果是 none 则返回 nilunwrap() 方法:强制解包值,如果是 none 则抛出一个错误。

实现可选链

我们可以实现 mapflatMap 的简化版本来支持可选链:

extension CustomOptional {
    // MARK: - 可选链
    // map,如果包装的值存在,则使用提供的转换闭包来转换值
    func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> CustomOptional<U> {
        switch self {
        case .some(let wrapped): // 有值转换
            return .some(try transform(wrapped))
        case .none: // 无值返回 none
            return .none
        }
    }

    func flatMap<U>(_ transform: (Wrapped) throws -> CustomOptional<U>) rethrows -> CustomOptional<U> {
        switch self {
        case .some(let wrapped):
            return try transform(wrapped) // 有值转换
        case .none:
            return .none // 无值返回 none
        }
    }
}

mapflatMap:这些方法提供了可选链的简化版本:

  • map:如果包装的值存在,则使用提供的转换闭包来转换值。

  • flatMap:跟 map 类似,区别在于转换闭包返回的是一个 CustomOptional 类型。

将我们的自定义 Optional 使用起来

现在我们可以使用我们的 CustomOptional 类型了:

let someValue: CustomOptional<Int> = .some(42)
let noValue: CustomOptional<Int> = .none

// 访问值
print(someValue.value) // Optional(42)
print(noValue.value) // nil

// 解包
do {
    let unwrapped = try someValue.unwrap()
    print(unwrapped) // 42
} catch {
    print("Error unwrapping: \(error)")
}

// 可选链
let doubled = someValue.map { $0 * 2 }
print(doubled.value) // Optional(84)

let stringified = someValue.flatMap { value in
    CustomOptional<String>.some(String(value))
}
print(stringified.value) // Optional("42")

实现我们的 CustomOptional 类型可以深入了解 Swift 的 Optionals 在底层大概是如何实现的。虽然这个实现并不包括 Swift 内置 Optionals 的所有特性(比如 ?? 操作符或隐式解包),但它涵盖了核心功能,并展示了 Swift 中代数数据类型的强大力量。

希望这篇文章对你理解 Swift 的 Optionals 有所帮助,如果你有任何问题或建议,欢迎在评论区告诉我们!

这里每天分享一个 iOS 的新知识,快来关注我吧

本文同步自微信公众号 “iOS新知”,每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!

注册登录 后评论
    // 作者
    iOS新知 发布于 掘金
    • 0
    // 本帖子
    分类
    // 相关帖子
    Coming soon...
    • 0
    Swift 开发新高度:自己动手实现 Optional 类型iOS新知 发布于 掘金