Swift 编程思想 Part 4:map all the things!
Swift 编程思想 Part 4:map all the things!
2015-10-22 837
作者:Olivier Halligon,原文链接,原文日期:2015-10-11
译者:ray16897188;校对:Prayer;定稿:numbbbbb
系列文章地址:
在本系列之前的文章中我们学到了如何使用map
和flatMap
来操作数组(arrays)。今天我们继续研究如何对可选类型(Optionals)以及很多其他类型使用map
和flatMap
。
数组 vs. 可选类型
回顾一下,学完前面的文章后我们已经知道,Array<T>
对应的map()
和flatMap()
函数签名是:
1 |
// 作用在Array<T>上的方法 |
意思是你可以用一个给定的transform: T->U
将一个元素类型是T
的数组转换成一个元素类型是U
的数组。对Array<T>
调用map( transform: T->U )
方法就会返回一个Array<U>
,就这么简单。
嗯,不出意外,对于Optional<T>
来说,map()
和flatMap()
的函数签名十分类似:
1 |
// 作用在Optional<T>上的方法 |
是不是很像?
作用在可选类型上的 map()
那么map
方法到底对Optional<T>
类型(也叫做T?
)做了什么?
其实很简单:和作用在Array<T>
上的一样,map
方法将Optional<T>
中的内容取出来,用指定的transform: T->U
方法做出转换,然后把结果包装成一个新的Optional<U>
。
如果细想一下,这和Array<T>.map
做的事情十分相似:这个方法对Array<T>
(与之相应的是Optional<T>
)中的每个元素使用transform
函数转换,并将转换过的值封装在一个新的Array<U>
中(与之相应的是Optional<U>
),作为结果返回。
回到我们的例子
那么这对我们一直在做的示例代码有什么帮助?
在我们最新版代码中,有一个String?
类型的itemDesc["icon"]
,我们当时想把它转换成一个UIImage
;但是UIImage(named:)
要求传入一个String
型的参数,而不是String?
型,所以我们需要在可选型中确实有值时(非nil
)将内部的String
值传入。
一种解决方案是使用可选绑定(Optional Binding):
1 |
let icon: UIImage? |
但是对于一个如此简单的操作来说代码量太大。
之前的一个例子中我们用了另外一种(很不优雅的)方式,使用nil
-联合操作符??
。
1 |
let iconName = itemDesc["icon"] as? String |
这么做是可以,但是之所以能够成功,是因为当iconName
是nil
时,我们实际上是使用了UIImage(named: "")
的初始化方法,这个初始化方法在传入空字符串时,会返回nil
。但是这样的解决办法不是很好,因为我们是依赖于该初始化方法的特性(传入空字符串时,会返回nil
)来实现的。
来用 map 吧
那么为什么不用map
呢?本质上,我们是想要在Optional<String>
不是nil
的时候将其解包,把里面的值转换成一个UIImage
对象然后把这个UIImage
返回,这不就是一个绝佳的用例么?
试试看:
1 |
let iconName = itemDesc["icon"] as? String |
等会儿…. 编译不通过。能猜出为什么吗?
哪儿有问题?
上面的代码中的问题是UIImage(named: …)
也返回一个可选类型:如果对给定的name
没有相应的图片,就不能创建出一个UIImage
,所以这种情况下该初始化方法为可失败的(failable),并返回nil
,是完全合理的。
于是问题就在于我们给map
的这个闭包用一个String
作为参数而返回…一个UIImage?
类型——因为图片的初始化方法是可失败的,会返回nil
。再看一下map
方法的签名,它想要的是一个T->U
类型的闭包,这个闭包会返回一个U?
类型。我们的例子中,U
代表UIImage?
的话,整个map
表达式会返回一个U?
类型,也就是…一个UIImage??
类型…是的,一个双重可选类型,吓死宝宝了!
flatMap() 来帮忙了
flatMap()
与map
类似,但是做的是一个T->U?
的转换(不是T->U
),它把结果“扁平化(顾名思义)”成一个单重的可选类型。这恰恰就是我们所需要的!
1 |
let iconName = itemDesc["icon"] as? String |
实际中flatMap
做了如下工作:
- 如果
iconName
是nil
的话,它就直接返回nil
(但返回类型还是UIImage?
) - 如果
iconName
不是nil
,它就把transform
作用到iconName
的实际的值上,尝试用这个String
创建一个UIImage
并将结果返回——结果本身已经是一个UIImage?
类型,因此如果UIImage
初始化方法失败的话,返回结果就是nil
。
简而言之,item.icon
只会在itemDesc["icon"] as? String
非空、并且UIImage(named: imageName)
初始化方法成功的情况下才是一个非空值。
和使用??
欺骗初始化方法相比,这么做更好,更地道。
把 init 当闭包来用
更进一步,由于现在 Xcode 7 可以通过类型的.init
属性暴露该类型的构造器(constructors),上面的代码还能写的更加紧凑。
这意味着UIImage.init
本质上就已经是一个接收String
并返回UIImage?
的方法了,所以我们可以把它直接当成参数来调用flatMap
,不用把它再包进一个闭包里!
1 |
let iconName = itemDesc["icon"] as? String |
哇哦!太魔幻了!
好了,有人说这么写很难读懂,为了让代码更明了更清晰,在这里还是更喜欢用一个显式闭包。但是这只是关乎个人偏好,并且知道这么做可行也是好事。
最终的Swift代码
下面就是将本课所学应用到之前代码里的样子:
1 |
struct ListItem { |
回头看一眼我们的 ObjC 代码
花一点儿时间比较一下我们最终的 Swift 代码和最开始的ObjC代码。我们着实改了很大一部分内容。
如果你仔细看一下 ObjC 和 Swift 代码,会发现 Swift 的代码量并不是那么少(ObjC 是 5+15 LoC1,对比 Swift 的 19 LoC),但是安全性高了太多。
尤其是我们使用的guard
,try?
和as?
会迫使我们去检查所有类型是否都如所期,ObjC 代码不会关心这些,因此可能崩溃
Swift 编程思想 Part 4:map all the things!的更多相关文章
- Swift 编程思想 阅读笔记
Swift 编程思想,第一部分:拯救小马html, body {overflow-x: initial !important;}.CodeMirror { height: auto; } .CodeM ...
- [Hadoop入门] - 1 Ubuntu系统 Hadoop介绍 MapReduce编程思想
Ubuntu系统 (我用到版本号是140.4) ubuntu系统是一个以桌面应用为主的Linux操作系统,Ubuntu基于Debian发行版和GNOME桌面环境.Ubuntu的目标在于为一般用户提供一 ...
- Java编程思想(11~17)
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第十一章 持有对象 11.1 泛型和类型安全的容器>eg: List<St ...
- Java编程思想 (1~10)
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第一章 对象导论 1.万物皆对象2.程序就是对象的集合3.每个对象都是由其它对象所构成 ...
- Java编程思想总结笔记The first chapter
总觉得书中太啰嗦,看完总结后方便日后回忆,本想偷懒网上找别人的总结,无奈找不到好的,只好自食其力,尽量总结得最好. 第一章 对象导论 看到对象导论觉得这本书 目录: 1.1 抽象过程1.2 每个对象 ...
- Java编程思想读书笔记(一)【对象导论】
2018年1月7日15:45:58 前言 作为学习Java语言的经典之作<Java编程思想>,常常被人提起.虽然这本书出版十年有余,但是内容还是很给力的.很多人说这本书不是很适合初学者,我 ...
- Java编程思想(后)
Java编程思想(后) 持有对象 如果一个程序只包含固定数量的且其生命期都是已知的对象,那么这是一个非常简单的程序. Java中的库基本类型: List, Set, Queue和Map --- 称为集 ...
- Java编程思想(前十章)
Java编程思想 有C++编程基础的条件下, 前10章可以快速过一下,都是基本语法,不需要花太多时间. 着重中后段的一些章节,类型信息.泛型.容器.IO.并发等. 中文翻译版 阅读地址 对于一个架构师 ...
- javaWeb中MVC的编程思想示例
没有学习MVC之前我只写了一个Servlet类(Note_List.java),分层之后,我将这个类分成了5个类(NoteDao.java,,NoteDaoImpl.java,,NoteService ...
随机推荐
- bzoj 2597: [Wc2007]剪刀石头布【最小费用最大流】
脑子不太清楚一个zz问题调了好久-- 首先正难则反,因为三元环好像没什么特点,就考虑让非三元环个数最小 考虑非三元环特点,就是环上一定有一个点的入度为2,联系整张图,三元环个数就是每个点C(入度,2) ...
- bzoj 2738: 矩阵乘法【整体二分+树状数组】
脑子一抽开始写主席树,敲了一会发现不对-- 整体二分,用二维树状数组维护值为当前区间的格子个数,然后根据k的大小和当前询问的子矩阵里的值和k的大小关系来决定这个询问放在哪一部分向下递归 #includ ...
- IT兄弟连 JavaWeb教程 JSTL常用标签
1.条件标签 条件标签能够实现Java语言中的if语句以及if-else语句的功能,它包括以下几种: <c:if>:用于实现Java语言中的if语句的功能. <c:choose> ...
- java操作mongodb数据库实现新建数据库,新建集合,新建文档
*首先明确一点,要通过java代码创建mongodb数据库实例,需要同时创建集合和文档. 代码实现: /* 建立与mongodb数据库的连接,可指定参数,如:MongoClient client = ...
- 最大xor,and,or
http://210.33.19.103/contest/998 and,or部分 并不用01trie,题目&题解:https://blog.csdn.net/dreaming__ldx/ar ...
- 利用Common-Fileupload上传文件图片
一,介绍 common-fileupload是appache的开源组件,基于该组件可以轻松实现文件上传的功能,strust框架的文件上传功能也是基于该组件. 二,使用 1,导入两个jar包:commo ...
- 剑指offer部分编程题
一 斐波那契数列 题目描述: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项. n<=39 问题分析: 可以肯定的是这一题通过递归的方式是肯定能做出来,但是这样会有 ...
- Memcached 未授权访问漏洞及加固
memcached是一套分布式的高速缓存系统.它以Key-Value(键值对)形式将数据存储在内存中,这些数据通常是应用读取频繁的.正因为内存中数据的读取远远大于硬盘,因此可以用来加速应用的访问. 漏 ...
- Nodejs chrome 调试node-inspector
1.下载扩展: 全局安装 npm install -g node-inspector 2.开启debug调试: node --debug[=port] filename (默认端口5858)node ...
- sql 使用汇总(PQSQL)
--sql structured query language --DML--Data Manipulation Language--数据操作语言 query information (SELECT) ...