闭包在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. list接口如何使用

    1集合类,在java语言中的java.util包提供了一些集合类,这些集合类又被称作容器. 2区别集合类和数组.(1)数组的长度是固定的,集合的长度是可变的.(2)数组是用来存放基本数据类型的,集合是 ...

  2. mongodb first

    use [database] 使用数据库,新增文档后,数据库被自动创建 show dbs 显示所有数据库 db.[document].insert() 插入数据库 例:db.persons.inser ...

  3. 判断TrueType字体

    function IsTrueTypeFont(FontName : string) : boolean;const  PITCH_MASK: byte = $0F;  var  TxMetric: ...

  4. SQL 2008维护计划不执行的问题

    平台环境; 先是装了WINDOWS 2008,没有升级到AD,再安装了sql2008后再升级了AD. 现在SQL建了几个数据库备份计划,但都提示下面的信息: 日期  2010-4-15 9:36:00 ...

  5. Hadoop 集群的一些问题

    1.创建用户hadoop adduser hadoop passwd hadoop usermod -a -G hadoop hadoop chown -R hadoop:hadoop  /data ...

  6. cf-Round542-Div2-B(贪心)

    题目链接:http://codeforces.com/contest/1130/problem/B 思路: 贪心题.定义结构体数组a,a[i].x[0],a[i].x[1]分别表示i出现的第一个下标和 ...

  7. Extjs Vbox布局方式,以及align种类,flex,pack属性含义简介

    VBox布局方式,熟悉下一下几个主要属性: 一.align:字符类型,指示组件在容器内的对齐方式.这个是基于容器的左上角来排列的.pack不同,pack是根据容器的最上边来显示的. 1.left(默认 ...

  8. Spring框架的事务管理之基于AspectJ的注解方式(重点掌握,最简单的方式)

    1. 步骤一:恢复转账的开发环境(具体开发环境实现见:https://www.cnblogs.com/wyhluckdog/p/10137283.html)2. 步骤二:applicationCont ...

  9. 原生JS获取url汇总

    在WEB开发中,许多开发者都比较喜欢使用javascript来获取当前url网址,本文就此为大家总结一下比较常用获取URL的javascript实现代码 URL即统一资源定位符 (Uniform Re ...

  10. tp5允许跨域

    header("Access-Control-Allow-Origin: *"); 放在命名空间之后