Optional 中的 map 和 flatMap

栏目: IOS · 发布时间: 5年前

内容简介:在面试的时候,面试官问了我一个问题。你使用过 Optional 吗?Optional 的原理是什么?我一听,这还不简单。然后面试官又问,那你使用过首先,我试用了一下的代码来测试

在面试的时候,面试官问了我一个问题。你使用过 Optional 吗?Optional 的原理是什么?我一听,这还不简单。 Optional 是一个枚举。

public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
}
复制代码

然后面试官又问,那你使用过 OptionalmapflatMap 吗。我一般是在 Sequence 里使用 mapflatMap 的。在 Optional 里还真没用过。所以在面试之后,赶紧来补习一波。

首先,我试用了一下的代码来测试

let h: Int? = 10
let h1 = h.map { $0 + 2}
let h2 = h.flatMap { $0 + 2}
print(h1) // Optional(10)
print(h2) // Optional(10)
复制代码

咦,好像没区别?好吧,换种测试方法,在闭包里再转成一个 Optional 看一下

let g: String? = "10"
let g1 = g.map {Int($0)}
let g2 = g.flatMap {Int($0)}

print(g1) // Optional(Optional(10))
print(g2) // Optional(10)
复制代码

嗯,这次的返回的结果就不一样了。 flatMap 对结果做了一次展开。那它是怎么做到的呢?源代码在 githubswift/stdlib/public/core/Optional.swift 文件里。来看一下这2个方法的源代码有什么区别吧。

public func map<U>(
    _ transform: (Wrapped) throws -> U
  ) rethrows -> U? {
    switch self {
    case .some(let y):
      return .some(try transform(y))
    case .none:
      return .none
    }
  }
复制代码
public func flatMap<U>(
    _ transform: (Wrapped) throws -> U?
  ) rethrows -> U? {
    switch self {
    case .some(let y):
      return try transform(y)
    case .none:
      return .none
    }
复制代码

一眼看上去,2个方法的实现只有2处不一致。一处是方法签名

func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?      
func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?
复制代码

另一处是当有值的时候的返回值

return .some(try transform(y)) // map
return try transform(y) // flatMap
复制代码

但我们一般申明一个 Optional 的返回值时,如果是一个确定的值,也可以直接返回。编译器会帮你包装成 .some() 的形式。所以这里 map 方法里的代码也可以写成和下面的 flatMap 方法一致。

那么这样看来,就只有方法签名不一致了,那它到底是怎么实现的呢?这里我们就以上面的例子,把泛型转成具体的类型来看一下吧。

在上述方法里, map 方法 transform 闭包的返回值是 Int($0) ,是一个 Int? 的类型,那么 U 就是一个 Int? , U? 就是 Int?? 。所以转成具体类型之后,方法签名变成了

func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?      
func myMap(_ transform: (Wrapped) throws -> Int?) rethrows -> Int??
复制代码

flatMap 方法 tranform 的返回值签名是 U? ,对应 Int? ,那么这里 U 就是 Int ,所以 flatMap 方法的方法签名就变成了

func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?
func myFlatMap(_ transform: (Wrapped) throws -> Int?) rethrows -> Int?
复制代码

这样一看是不是就一目了然了。只能说 swift 的泛型机制真是太强大太巧妙了。我修改签名的源代码放在下面,有兴趣的可以跑起来看看

extension Optional {
    func myMap(_ transform: (Wrapped) throws -> Int?) rethrows -> Int?? {
        switch self {
        case .some(let y):
            return try transform(y)
        case .none:
            return .none
        }
    }
    
    func myFlatMap(_ transform: (Wrapped) throws -> Int?) rethrows -> Int? {
        switch self {
        case .some(let y):
            return try transform(y)
        case .none:
            return .none
        }
    }
}
复制代码

以上所述就是小编给大家介绍的《Optional 中的 map 和 flatMap》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

特斯拉之父

特斯拉之父

竹内一正 / 千太阳 / 中信出版社 / 2014-12 / 39.00

马斯克的成就前无古人地跨越了各个领域,曾大起大落,成为亿万富翁后,又曾濒临破产。他凭借极强的控制欲、坚强的意志力把人生浓缩得异常精彩,拓展了人类对自身智力与能力限度的想象。乔布斯离开了,马斯克来了,后者离人更远,离神更近。 他的创业故事就是一部真实的好莱坞大片 美国《财富》杂志 “2013年度商业人物” 史上最富激情、传奇、未来感的企业家 他是个外表优雅的生意人、太空的挑战......一起来看看 《特斯拉之父》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器