Swift中的闭包(Closure) 浅析
转载自:http://www.devtalking.com/articles/closure-expressions-in-swift/
闭包在Swift中非常有用。通俗的解释就是一个Int类型里存储着一个整数,一个String类型包含着一串字符,同样,闭包是一个包含着函数的类型。有了闭包,你就可以处理很多在一些古老的语言中不能处理的事情。这是因为闭包使用的多样性,比如你可以将闭包赋值给一个变量,你也可以将闭包作为一个函数的参数,你甚至可以将闭包作为一个函数的返回值。它的强大之处可见一斑。
在Swift的很多文档教材中都说函数是“一等公民”,起初我还不是很理解“一等公民”是什么意思,但当我理解了闭包以及它的强大功能后,我恍然大悟、茅塞顿开、醍醐灌顶。原来闭包的这些特性就是“一等公民”的特性啊!参见维基百科First-class citizen。
Swift中的闭包类似Objective-C中的Block。其实,如果你想在Swift中实现Objective-C里的Block功能,你可以直接使用闭包来代替。Block和闭包的区别只是语法的不同而已,而且闭包的可读性比较强。
函数是闭包吗?
虽然你还没有意识到,但我们确实已经在Swift中这么用了。Swift中的函数就是闭包,在Apple的官方文档中有这样的描述:
闭包有三种形式:
- 全局函数是一个有名字但不会捕获任何值的闭包。
- 嵌套函数是一个有名字并可以捕获到其封闭函数域内的值的闭包。
- 闭包表达式是一个利用轻量级语法所写的,可以捕获其上下文中变量或常量值的匿名闭包。
今天,我们要讨论的是第三种形式,尤其讨论它是如何将繁复的、可读性比较差的业务逻辑代码压缩成高可读性、简明明了的形式。
大家还记得数组的map方法么?它的参数就是一个闭包,它会将数组里的每一个元素放在闭包中进行处理,然后返回一个新的数组,甚至是与原数组不同元素类型的新数组。
map函数的原型如下:
func map<U>(transform: (T) -> U) -> [U] |
我们可以看到该函数使用了泛型。(T) -> U是一个泛型闭包,它的意思就是类型T将会在闭包中进行逻辑处理,然后返回U类型。最后map函数会返回一个U类型的数组。
用一个例子来说明。今天我办生日聚会,要迎接很多人,并且为每个人都准备了一句欢迎词。我们要怎么做呢?首先我们将迎接的人放进一个数组名叫guestList,然后用一个名叫greetPeople的函数为每个人生成欢迎词:
func greetPeople(person: String) -> String |
然后将greetPeople函数作为guestList数组的map函数的参数传入,并返回一个新的数组fullGreetings,这个数组就包含了每个人的欢迎词。
如果我们想展示一下每个人的欢迎词,我们甚至可以这样写:
fullGreetings.map(println) |
这时也许有人要质疑了,println函数不是没有返回值么?那么map函数会返回什么呢?其实每一个没有返回值的函数,都会返回一个空的元组(tuple),所以说上述代码的返回值其实是Array<()>。
上面的例子中我们就是将一个全局函数greetPeople作为一个闭包来使用的。
简明扼要的闭包表达式
其实Swift已经为我们提供了很多简化的语法,可以让我们保证代码的高可读性和维护性。还用上面的例子来说明,对于greetPeople这个全局函数来说,其实只需要使用一次,所以我们没必要单独定义这个函数。我们可以直接使用闭包表达式来处理:
let fullGreetings = guestList.map({(person: String) -> String in return "Hello, \(person)!"})
|
闭包表达式其实是函数的字面值,官方一般称之为匿名函数。一般当我们需要使用函数快速的实现一个简短的处理逻辑并且只使用一次的时候,我们可以省去函数名,使用简化的语法。上面的代码中可以看到关键字in之前是闭包表达式的参数和返回值,in之后是闭包表达式实际处理逻辑的代码区域。
下面我们将使用Swift更多的特性来进一步简化闭包表达式。
我们知道Swift中有类型推断的特性,所以我们可以取掉参数类型:
let fullGreetings = guestList.map({(person) -> String in return "Hello, \(person)!" })
|
像我们示例中的这种单一闭包表达式,编译器可以根据in之前的返回值类型和return之后的返回数据类型自动判断,所以我们可以省略返回值和return关键字:
let fullGreetings = guestList.map({person in "Hello, \(person)!" })
|
其实在Swift中还提供了参数的简写方式:$0代表第一个参数、$1代表第二个参数以此类推。所以我们又可以将参数名称省略:
let fullGreetings = guestList.map({ "Hello, \($0)!" })
|
当函数的最后一个参数是闭包时,可以将闭包写在()之外,这也是Swift的一个特性,所以我们还可以继续简化:
let fullGreetings = guestList.map(){ "Hello, \($0)!" }
|
当函数有且仅有一个参数,并该参数是闭包时,不但可以将闭包写在()外,还可以省略():
let fullGreetings = guestList.map{ "Hello, \($0)!" }
|
到目前为止,示例中的闭包表达式已经被我们根据Swift的特性,简化为简明扼要、高可读性的闭包表达式了,是不是很酷呢!
Swift中的闭包(Closure) 浅析的更多相关文章
- Swift中的闭包(Closure)[转]
闭包在Swift中非常有用.通俗的解释就是一个Int类型里存储着一个整数,一个String类型包含着一串字符,同样,闭包是一个包含着函数的类型.有了闭包,你就可以处理很多在一些古老的语言中不能处理的事 ...
- Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較类似。
闭包是功能性自包括模块,能够在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較相似. 闭包能够 捕获 和 ...
- swift中的闭包总结
闭包是功能性自包含模块,可以在代码中被传递和使用. Swift 中的闭包与 Objective-C中的 blocks 以及其他一些编程语言中的 lambdas 比较相似. 闭包的基本语法 闭包表达式语 ...
- Swift基础之闭包Closure学习
首先Swift语言中没有了Block内容,但是你可以通过调用OC文件使用,也可以使用Closure(闭包),实现Block或者Delegae同样反向传值或回调函数的效果,也可以解决函数指针的问题,两者 ...
- [Swift]UIAlertController 以及 Swift 中的闭包和枚举
原文地址:http://blog.callmewhy.com/2014/10/08/uialertcontroller-swift-closures-enum/ 在 iOS8 的 SDK 中, UIK ...
- SwiftCafe 咖啡时光 - 了解 Swift 中的闭包
闭包(Closure) 是现代开发语言的必备特性,极大的提高了我们的开发效率. 关于闭包,你可以把它理解为一种特殊的变量或对象.简而言之,我们通常的对象,里面存储的是变量或对象的值,而闭包里面存储的是 ...
- Swift中方法闭包参数不能省略括号的一种情况
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在swift中,如果方法的最后一个参数是一个闭包类型, ...
- javascript中的闭包closure详解
目录 简介 函数中的函数 Closure闭包 使用闭包实现private方法 闭包的Scope Chain 闭包常见的问题 闭包性能的问题 总结 简介 闭包closure是javascript中一个非 ...
- 说说Python中的闭包 - Closure
转载自https://segmentfault.com/a/1190000007321972 Python中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西 ...
随机推荐
- C++primer第三章标准库类型
除第二章介绍的基本数据类型外,C++ 还定义了一个内容丰富的抽象数据类型标准库. 本章将介绍标准库中的 vector.string 和 bitset 类型. string 类型支持长度可变的字符串 v ...
- onmousedown活用之鼠标拖动
这个布局蛮简单的就是一个div块,通过定位,固定位置 <html> <head> <meta charset="UTF-8"> <titl ...
- CentOS7 emacs安装
首先安装依赖库 依赖库: yum install gcc* yum install glib* yum install gtk* yum install ncurses* yum ...
- java基础算法题
为了提高自己的代码能力和算法能力,我决定每天学习一道算法题,吸收前辈思想. [程序1] TestRabbit.java 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三 ...
- angular模拟elema网页1
我们之前做的所有的网页项目都用的是假的json数据,真正的前后端的数据交互是个什么情况的呢?现在,我们就来看看. 首先,我们需要进行环境窃取,我们需要一个真实的数据,但是人家公司肯定不会将数据给你的, ...
- 【第四篇】androidEventbus源代码阅读和分析
1,分析androidEventbus的注册源代码: 我们在使用androidEventbus的第一步是注册eventbus,如下代码: EventBus.getDefault().register( ...
- POJ 3419 Difference Is Beautiful
先处理出每一个i位置向左最远能到达的位置L[i].每一次询问,要找到L,R区间中的p位置,p位置左边的L[i]都是小于L的,p位置开始,到R位置,L[i]都大于等于L,对于前者,最大值为p-L,后者求 ...
- 编写一个闹钟和定时关机工具(MFC VS2010)
这个小工具在自己生活当中能用到,运行软件以后,会显示当前的系统时间,然后你可以设定时间,再选择是定时响铃还是关机.截图如下: 前言:本程序采用visual studio 2010 ,对话框类型的应用程 ...
- thinkphp整合系列之phpexcel生成生成excel文件
在后台管理中会经常需要将数据生成excel表格的: php生成excel有两种方案: 一种是通过phpexcel生成xls格式的表格文件: 另一种则直接通过逗号换行生成csv格式的表格文件: 这里先讲 ...
- 《JS权威指南学习总结--3.1数字》
3.1数字 内容要点: 一.数字直接量:当一个数字直接出现在JS程序中,我们称之为数字直接量. 二.JS中的算术运算 Math.pow(2,53) // => 900719925474 ...