Swift:map(), flatMap() 和 compactMap() 的区别

该文章来自保罗·哈德森,解释了三种常见的功能方法。

Swift为我们提供了map()compactMap()flatMap()方法,但是尽管它们听起来很相似,但是它们做的却截然不同。在本文中,我们将介绍map()vscompactMap()vsflatMap(),以帮助您了解每个函数的作用以及何时有用。

这三种方法共享的单词是map,在此上下文中表示“从一个转换为另一个物体。”

map() : 转换

  • map()方法使我们可以编写代码以将数组中的所有数字加倍:
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }

这将获取数组中的每个值并通过我们的闭包运行,其中$0表示当前获取到的数字。因此,它将是1 * 2、2 * 2、3 * 2,依此类推 -map()将从其容器中取出一个值($0),使用您指定的代码对其进行转换,然后将其放回其容器中。在这种情况下,这意味着从数组中取出一个数字,将其加倍,然后将其放回新的数组中。

  • 它适用于任何数据类型,因此我们可以使用它来大写字符串数组:
let wizards = ["Harry", "Hermione", "Ron"]
let uppercased = wizards.map { $0.uppercased() }
  • map()能够返回与最初使用的类型不同的类型。因此,这会将我们的整数数组转换为字符串数组:
let numbers = [1, 2, 3, 4, 5]
let strings = numbers.map { String($0) }
如果我们尝试将这些字符串转换回整数,事情会变得有些棘手

这是因为字符串可以包含任何值:“ 1”,“ 5”和“ 500”都是可以安全地转换为整数的字符串,而“ Fish”则不能。所以通过map()将字符串转换为整数将返回可选的整数Int?

  • 如下代码可以展示上面的结论,此代码使用map()将字符串数组转换为可选整数数组[Int?]
let maybeNumbers = strings.map { Int($0) }
//maybeNumbers 类型为 [Int?]

compactMap(): 转换然后解包

使用可选值可能会很烦人,但是compactMap()可以使生活变得更加轻松:它执行转换(其名称的"map"部分),但随后解包所有可选选项并丢弃nil值。
  • 因此,以下代码行将相同的字符串转换为整数,但是会得到一个整数数组[Int]而不是一个可选整数数组[Int?]
let definitelyNumbers = strings.compactMap { Int($0) }
//definitelyNumbers 类型为 [Int]

Swift中有非常多地方会返回可选值,包括try?, as?,以及所有的失败的初始化构造器比如从一个整型创建字符串----这些都是非常好的可以使用compactMap()的情况。

  • 例如,如果你有一个UIView并想读出所有子视图中的UIImageView,则可以这样写:
let imageViews = view.subviews.compactMap { $0 as? UIImageView }
  • 或者,如果您有一个字符串数组,并且想知道哪些是有效的URL,则可以这样写:
let urls = urlStrings.compactMap { URL(string: $0) }

因此:map()将从其容器中取出一个值,使用您指定的代码对其进行转换,然后将其放回其容器中。compactMap()做同样的事情,但是如果您的转换返回一个可选值,它将被解包并丢弃所有nil值。

Optional map(): 仅当有值时转换

如果你想象一下,则可选对象类似于数组(其实是一个枚举包含.some 以及 .none):它们也是一个内部包含某些内容的容器。当我们查看可选容器内部时(解开可选容器时),我们找到一个值或找到nil

这意味着map()方法也存在于可选对象上:从容器中取出值(可选),使用我们提供的闭包对其进行转换,然后将其放回容器中(另一个可选对象)。如果可选参数为空,则map()不执行任何操作----它将返回nil

为了说明这一点,假设我们有一个getUser()方法,该方法接受一个整数并返回具有该ID的用户名(如果存在)。如果不存在,它将返回nil,因此此方法将返回一个可选字符串。

  • 我们可以使用map()读取发送回的值,并对其进行转换:
let name: String? = getUser(id: 97)
let greeting = name.map { “Hi, \($0)” }
print(greeting ?? “Unknown user”)

因此,如果name包含字符串,则map()会将解包,将其转换为“ Hi, name包含的字符串”,然后将整个拼接后的字符串放入一个可选对象中并返回以存储在greeting中。(如果name不包含字符串为nil,map()将直接返回nilgreeting。)所以返回值类型是String?

将值放回可选值中,可以使“也许它有一个值,也许没有”的情况持续更长的时间,以便以后的代码可以确定这意味着什么。在这种情况下,print()函数将打印问候或打印“Unknown user”-----它可以决定,而不是我们更早地强制设置“Unknown user”。

flatMap(): 转换然后展平

现在,你已经看到map()将整数数组转换为整数数组(将它们加倍),将整数数组转换为字符串数组,以及将字符串数组转换为整数数组。最后一个转换返回了可选的整数,因此我们还研究了compactMap()将如何执行相同的转换,但随后解包可选参数并丢弃所有nil值。

然后,我们研究了map()在可选对象上的工作方式:如果它具有一个值,则可以对其进行解包,转换和重新包装,但是如果它为nil,则保持为nil

  • 现在思考一下这段代码:
let number: String? = getUser(id: 97)
let result = number.map { Int($0) }
逐步进行操作-运行后会产生什么结果?
    1. number 是一个String?
    1. map()将值从可选值中取出然后转换
    1. 在这种情况下,Int($0)会将字符串转换为可选整数,因为字符串可能是非数字形式,例如“ Fish”。
    1. 然后,map()将该可选值放回另一个可选值中。

因此,当该代码运行时,结果将不是Int甚至是Int?–---它将是一个Int ??,这是一个可选的可选整数。广义上讲,任何时候当你看到可选的可选内容时,某个地方就已经出现了问题,你应该重新考虑。

要清楚,可选的可选意味着:
  • 1.外部可选项可能存在,而内部可选项可能存在.
  • 2.可能存在外部可选项,但内部可选项可能为nil。
  • 3.外部可选项可能为nil,这意味着没有内部可选项。
可选的可选参数使用起来非常混乱,但这就是flatMap()出现的地方:它不仅执行转换(其名称的“map”部分),但随后将返回的内容展平,因此“可选的可选参数”变为“可选的”。

也就是说,要么整个事物存在,要么不存在----它会将双重可选值变为单个可选值。最终,我们不在乎外部可选或内部可选是否存在,仅在乎其中是否存在值,这就是为什么flatMap()如此有用的原因。

  • 所以,此代码会将结果设置为Int?而不是Int ??
let number: String? = getUser(id: 97)
let result = number.flatMap { Int($0) }

以上内容来自保罗·哈德森What’s the difference between map(), flatMap() and compactMap()?

赏我一个赞吧~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容