Swift中的闭包(Closure)[转]
闭包在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)[转]的更多相关文章
- Swift中的闭包(Closure) 浅析
转载自:http://www.devtalking.com/articles/closure-expressions-in-swift/ 闭包在Swift中非常有用.通俗的解释就是一个Int类型里存储 ...
- 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中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西 ...
随机推荐
- zookeeper介绍以及安装配置
Zookeeper启动时默认将Zookeeper.out输出到当前目录,不友好.改变位置有两种方法: 1:在当前用户下~/.bash_profile或在/etc/profile,添加ZOO_LOG_D ...
- Haskell语言学习笔记(49)ByteString Text
Data.ByteString String 是 [Char] 的同义词,在使用上存在List的惰性所带来的性能问题. 在处理大型二进制文件时,可以使用 ByteString 来代替 String. ...
- Scala语言学习笔记(2)
表达式,值,变量,代码块,函数,方法 // 表达式 1 + 1 println(1 + 1) // 2 // 值(values)使用 val 关键字声明,带初值时类型可省略. val x = 1 + ...
- 机房servlet过滤器
1.源代码 loginform.html <html> <head> <title>使用过滤器改变请求编码</title> <meta http- ...
- js中声明函数的方法
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- (转)新手C#SQL语句的学习2018.08.13
1.创建数据库(create) CREATE DATABASE database-name 2.删除数据库(drop) drop database dbname 3.备份数据库 --- 创建 备份数据 ...
- IIS7配置下载apk以及目录浏览
IIS7为了增加安全性,如果需要禁止目录浏览.只需要按下面的步骤执行就可以 1.选择站点:2.选择功能视图:3.选择IIS下面的目录浏览:4.在右上角的操作中选择“打开功能”:5.选择右边的禁用. 今 ...
- Python3使用csv模块csv.writer().writerow()保存csv文件,产生空行的问题
问题:csv.writer().writerow()保存的csv文件,打开时每行后都多一行空行 解决方法:在open()内增加一个参数newline='' 即可 问题现象: 1.代码 with ...
- cmd命令 从C盘转到D盘
点开始 点运行.输入 CMD 回车.进入DOS提示符状态下.输入 cd\ 回车 表示进入 c:\> 也就是C盘根目录下.输入d: 回车 是进入D盘当前目录,并不一定是根目录.然后cd\ ...
- PHP下ajax跨域的解决方案之CORS
由于安全的限制(同源策略,javascript只能访问同域名下的内容),如果需要进行跨域操作,那就免不了要进行跨域. CORS(跨域资源共享,Cross-Origin Resource Shari ...