闭包在Swift中非常有用。通俗的解释就是一个Int类型里存储着一个整数,一个String类型包含着一串字符,同样,闭包是一个包含着函数的类型。有了闭包,你就可以处理很多在一些古老的语言中不能处理的事情。这是因为闭包使用的多样性,比如你可以将闭包赋值给一个变量,你也可以将闭包作为一个函数的参数,你甚至可以将闭包作为一个函数的返回值。它的强大之处可见一斑。

在Swift的很多文档教材中都说函数是“一等公民”,起初我还不是很理解“一等公民”是什么意思,但当我理解了闭包以及它的强大功能后,我恍然大悟、茅塞顿开、醍醐灌顶。原来闭包的这些特性就是“一等公民”的特性啊!参见维基百科First-class citizen

Swift中的闭包类似Objective-C中的Block。其实,如果你想在Swift中实现Objective-C里的Block功能,你可以直接使用闭包来代替。Block和闭包的区别只是语法的不同而已,而且闭包的可读性比较强。

函数是闭包吗?

虽然你还没有意识到,但我们确实已经在Swift中这么用了。Swift中的函数就是闭包,在Apple的官方文档中有这样的描述:

闭包有三种形式:

1. 全局函数是一个有名字但不会捕获任何值的闭包。

2. 嵌套函数是一个有名字并可以捕获到其封闭函数域内的值的闭包。

3. 闭包表达式是一个利用轻量级语法所写的,可以捕获其上下文中变量或常量值的匿名闭包。

今天,我们要讨论的是第三种形式,尤其讨论它是如何将繁复的、可读性比较差的业务逻辑代码压缩成高可读性、简明明了的形式。

大家还记得数组的map方法么?它的参数就是一个闭包,它会将数组里的每一个元素放在闭包中进行处理,然后返回一个新的数组,甚至是与原数组不同元素类型的新数组。

map函数的原型如下:

func map<U>(transform: (T) -> U) -> [U]

我们可以看到该函数使用了泛型。(T) -> U是一个泛型闭包,它的意思就是类型T将会在闭包中进行逻辑处理,然后返回U类型。最后map函数会返回一个U类型的数组。

用一个例子来说明。今天我办生日聚会,要迎接很多人,并且为每个人都准备了一句欢迎词。我们要怎么做呢?首先我们将迎接的人放进一个数组名叫guestList,然后用一个名叫greetPeople的函数为每个人生成欢迎词:

func greetPeople(person: String) -> String

{

return "Hello, \(person)!"

}

let guestList = ["Chris", "Jill", "Tim"]

let fullGreetings = guestList.map(greetPeople)

然后将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的特性,简化为简明扼要、高可读性的闭包表达式了,是不是很酷呢!

参考原文:Closure Expressions in Swift

Swift中的闭包(Closure)[转]的更多相关文章

  1. Swift中的闭包(Closure) 浅析

    转载自:http://www.devtalking.com/articles/closure-expressions-in-swift/ 闭包在Swift中非常有用.通俗的解释就是一个Int类型里存储 ...

  2. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較类似。

    闭包是功能性自包括模块,能够在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較相似.  闭包能够 捕获 和 ...

  3. swift中的闭包总结

    闭包是功能性自包含模块,可以在代码中被传递和使用. Swift 中的闭包与 Objective-C中的 blocks 以及其他一些编程语言中的 lambdas 比较相似. 闭包的基本语法 闭包表达式语 ...

  4. Swift基础之闭包Closure学习

    首先Swift语言中没有了Block内容,但是你可以通过调用OC文件使用,也可以使用Closure(闭包),实现Block或者Delegae同样反向传值或回调函数的效果,也可以解决函数指针的问题,两者 ...

  5. [Swift]UIAlertController 以及 Swift 中的闭包和枚举

    原文地址:http://blog.callmewhy.com/2014/10/08/uialertcontroller-swift-closures-enum/ 在 iOS8 的 SDK 中, UIK ...

  6. SwiftCafe 咖啡时光 - 了解 Swift 中的闭包

    闭包(Closure) 是现代开发语言的必备特性,极大的提高了我们的开发效率. 关于闭包,你可以把它理解为一种特殊的变量或对象.简而言之,我们通常的对象,里面存储的是变量或对象的值,而闭包里面存储的是 ...

  7. Swift中方法闭包参数不能省略括号的一种情况

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在swift中,如果方法的最后一个参数是一个闭包类型, ...

  8. javascript中的闭包closure详解

    目录 简介 函数中的函数 Closure闭包 使用闭包实现private方法 闭包的Scope Chain 闭包常见的问题 闭包性能的问题 总结 简介 闭包closure是javascript中一个非 ...

  9. 说说Python中的闭包 - Closure

    转载自https://segmentfault.com/a/1190000007321972 Python中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西 ...

随机推荐

  1. python classmethod 和 staticmethod的区别

    https://stackoverflow.com/questions/12179271/meaning-of-classmethod-and-staticmethod-for-beginner 1. ...

  2. 基于HttpClient的HttpUtils(后台访问URL)

    最近做在线支付时遇到需要以后台方式访问URL并获取其返回的数据的问题,在网络上g了一把,发现在常用的还是Apache的HttpClient.因为以经常要用到的原故,因此我对其进行了一些简单的封装,在此 ...

  3. margin和padding的四种写法

    我们经常会看到CSS样式属性中外边距margin和内边距padding的各种用法,这里做一个小结,但只简单介绍margin,因为它们的用法大同小异. 方法一. margin:10px; //4个外边距 ...

  4. 通过yumdownloader下载rpm包

    通过yum自带的一个工具:yumdownloader [root@web1 ~]#  rpm -qa |grep yum-utils [root@web1 ~]# yum -y install yum ...

  5. frame标签使用

    今天在做onebyone作业的时候,为了使自己的页面更加美观,我便使用了frame框架,百度了他的用法,总结如下 frame,是网页开发必须掌握的知识.例如后台架构.局部刷新,页面分割,都是frame ...

  6. Nunit常用的方法说明

    下来还是分为2个部分,一是NUnit的布局,另外一部分就是它的核心概念. 首先熟悉一下NUnit GUI的布局. 让我们更进一步看一下测试运行器窗口的布局.在右边面板的中间,可以看到测试进度条.进度条 ...

  7. pyplot图像组件

    pyplot图像组件 ax子对象的组件内容 Title 图表标题 plt.title() Axis 坐标范围,x轴,y轴 plt.axis() label 坐标轴标注 plt.xlabel() plt ...

  8. python的读写和写读操作

    # 读写操作 (读写操作是正常的)f = open('log',mode='r+',encoding='utf-8') # log是文件名 print(f.read()) f.write(" ...

  9. HttpClientUtil 工具类

    /* * * * FileName: s.java * * Description:TODO(用一句话描述该文件做什么) * * Created: jiangzhanghong 2017年11月14日 ...

  10. 大型运输行业实战_day10_1_自定义事务管理类

    1.创建事务管理类  TransactionManager.java package com.day02.sation.transaction; import com.day02.sation.uti ...