内容简介:[NSaylor简书作者]
Swift4 闭包及其应用
[
NSaylor
简书作者] 180_ NSaylor
2018-01-09 09:28 打开App
闭包 closure
闭包在Swift中应用广泛,在许多系统库方法中都能看到。
- 无名
- 本质是函数
- 使用时注意循环引用
闭包基础
//闭包是无名的,因为他们能够从上下文中捕获变量、常量,从而应用在自身的作用区域。 //声明 var myClosure: () -> String //注意 () -> String 实际上是一个无名函数,作为闭包变量的类型。 //无返回值的闭包 myClosure:() -> Void = { print("Hello world") } //执行闭包 myClosure() // Hello world //尝试一个带参的闭包 var mySecondClosure: (Int , Int ) -> Int = { (a: Int , b: Int) -> Int in return a * b } //第一次简化 类型自动推导 可以根据参数推断 mySecondClosure = { (a, b) in return a * b } //第二次简化 如果函数体只包含一句 return 代码,可省略 return mySecondClosure = { (a, b) in a * b } /* 第三次简化 被捕获的参数列表中,含有a、b,下标从0开始,可通过"$"获取。 编译器亦可通过,捕获列表自行推断出参数。 故可省略参数列表 (a, b)和 关键字 in */ mySecondClosure = { $0 * $1 }
闭包作为函数参数
/* operation: 是一个闭包类型的参数 该闭包有两个参数(Int, Int) ,并有一个Int型返回值 要整体看待,不要蒙圈。 */ func myOpreation(_ a: Int , _ b: Int, operation: (Int , Int) -> Int) -> Int { let res = operation(a, b) return res } //实现一个闭包 let multipyClosure:(Int, Int) -> Int = { $0 * $1 } //等同于 let multipyClosure = { (a: Int, b: Int) in a * b } //下面,我们将闭包作为参数传递 myOperation(4, 2, operation:multipyClosure) //展开 inline myOperation(4, 2, operation: { (a: Int, b: Int) -> Int in return a * b }) /* 事实上,我们并没有必要在本地定义一个闭包常量或变量,再作为参数传递。 可以简单的在调用的地方进行声明并简化 */ myOperation(4, 2, operation:{ $0 * $1 }) //进一步简化,* 操作符是一个有两个参数并返回一个结果的函数。可做如下简化: myOperation(4, 2, operation: *) /* 如果闭包是作为函数的最后一个参数,可以将闭包后置到函数体外部。 */ myOperation(4, 2) { $0 * $1 }
捕获
闭包可以从上下文环境中捕获常量、变量,并在自己的作用域内使用。
//eg.: 1 var counter = 0 let incrementCounter = { counter += 1 } /* 由于闭包定义和变量counter在同一作用域中, 故闭包可以捕获并访问变量counter。 对变量counter做的任何改变,对闭包来说都是透明可见的。 */ incrementCounter() //1 incrementCounter() //2 //eg.: 2 func countingClosure() -> () -> Int { var counter = 0 let incrementCounter: () -> Int = { counter += 1 return counter } return incrementCounter } /* 该例子中,闭包捕获了封闭空间(函数实体内)的内部变量counter。 */ let counter1 = countingClosure() let counter2 = countingClosure() counter1() // 1 counter2() // 1 counter1() // 2 counter1() // 3 counter2() // 2
应用闭包在集合中 排序
/* 数组提供了一个 排序 函数,sorted().使用的是默认规则,当然我们也可以定制排序规则。 */ let names = ["ZZZZZZ", "BB", "A", "CCCC", "EEEEE"] names.sorted() // ["A", "BB", "CCCC", "EEEEE", "ZZZZZZ"] //更改排序规则 其实就是利用了函数重载,具体可看函数定义 //sorted(by: <#T##(String, String) throws -> Bool#>) names.sorted { $0.count > $1.count } // ["ZZZZZZ", "EEEEE", "CCCC", "BB", "A"]
遍历
集合提供了很多遍历的函数用来对元素进行访问及操作,并大量应用了闭包。 重点需要了解的函数有: forEach、filter、map、reduce
- forEach
/* 循环遍历集合中的元素,相当于for-in 快速遍历 */ let values = [5, 3, 2, 3,1] values.forEach { print("element is \($0)") }
- filter
/* 函数原型: func filter(_ isIncluded: (Element) -> Bool) -> [Element] 按照规则过滤原数组 */ var values = [1.5, 10, 4.88, 3.2, 8] let res = values.filter { return $0 > 4 } //res是移除掉小于或等于4的元素的新数组
- map
/* 函数原型: students.map(<#T##transform: (String) throws -> T##(String) throws -> T#>) 数组映射 */ let input = ["0", "12", "name", "hi", "3"] let number = input.map { Int($0) //将元素转换为Int型 } //注意类型转换可能失败,所以返回的是可选型 //[Optional(0), Optional(12), nil, nil, Optional(3)] /* 另外一个高度近似的函数 flatMap 隐含了两种操作 1.解包 2.展开并合并 */ let flatNumber = input.flatMap() { Int($0) } //[0, 12, 3]
- reduce
/* 函数原型 reduce(<#T##initialResult: Result##Result#>, <#T##nextPartialResult: (Result, String) throws -> Result##(Result, String) throws -> Result#>) */ //数组 let flatNumber = [0, 12, 3] let sum = flatNumber.reduce(0) { return $0 + $1 } //15 //字典 let stock = [1.5: 5, 10: 2, 4.99: 20, 2.30: 5, 8.19: 30] let stockSum = stock.reduce(0) { return $0 + $1.key * Double($1.value) } //384.5 /* 另一个reduce重载函数 注意inout 关键字,所以想想你可以怎么应用? */ input.reduce(into: <#T##Result#>) { (<#inout Result#>, <#String#>) in <#code#> }
9
© 著作权归作者所有
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beginning Java Objects中文版从概念到代码
巴克 / 万波 / 人民邮电出版社 / 2007-1 / 78.00元
《Beginning Java Objects中文版从概念到代码(第2版)》是关于软件对象和Java的,但并不是纯粹地介绍Java语言,而是强调如何从对象模型转换到功能完整的Java应用程序。书中讲述了对象基础、对象建模和模型的实现。《Beginning Java Objects中文版从概念到代码(第2版)》除了用学生注册系统(SRS)示例贯穿全书之外,还在附录中给出三个附加的案例,这些案例是每章......一起来看看 《Beginning Java Objects中文版从概念到代码》 这本书的介绍吧!