如果你是函数式编程的入门者,你一定听说过高阶函数。它在维基百科中的中文解释是这样的:在数学和计算机科学中,高阶函数是至少满足以下条件之一的函数:接受一个或多个函数作为输入和输出一个函数看起来像是一个输入参数在ObjC语言中或者返回值是块的块或者函数,在Swift语言中就是输入参数或者返回值是函数的函数。那么他们在实际的开发过程中分别扮演了怎样的角色呢?我们将从入参、返回值、综合使用三个部分来看这个问题:函数作为入参函数作为入参似乎无论在ObjC时代还是Swift时代都是司空见惯的事情。例如,AFNetworking使用两个输入块分别回调成功和失败。Swift中增加了一个尾部闭包语法(最后一个参数是一个函数,可以不写括号也可以直接跟在括号外的方法名后面),例如:[1,2,3].forEach{iteminprint(item)}我们可以把输入参数为函数的函数分为两类,escape函数输入参数和noescape函数输入参数。区别在于输入参数函数是在执行过程中调用还是在执行过程外调用。在执行过程外调用一般用于回调目的,例如:Alamofire.request("https://httpbin.org/get").responseJSON{responseinprint(response.request)//originalURLrequestprint(response.response)//HTTPURLresponseprint(response.data)//serverdataprint(response.result)//resultofresponseserializationifletJSON=response.result.value{print("JSON:\(JSON)")}}这个response的输入函数作为回调返回网络请求,执行responseJSON函数时不会被调用。另外,我们观察一下forEach的代码。可以推断,作为参数输入的函数在forEach的执行过程中肯定会用到。执行后就没用了。这个类型就是noescape函数。您应该熟悉回调的用法。下面介绍一下noescape入参的一些用法:1.免构造函数看过GoF设计模式的同学不知道还记得构造函数模式吗。Android中的构造函数模式类似于以下内容:newAlertDialog.Builder(this).setIcon(R.drawable.find_daycycle_icon).setTitle("Reminder").create().show();构造一个对象需要很多参数,其中很多参数都有默认值,而这些参数对应的属性在以后如果不想被修改,可以使用这种模式来直观细腻的展示构造过程.如果使用noescape输入函数,可以更简单地构造这种代码,只需要传入一个输入参数为builder的对象,如下://这里实现classSomeBuilder{varprop1:Intvarprop2:Boolvarprop3:Stringinit(){//defaultvalueprop1=0prop2=trueprop3="somestring"}}classSomeObj{privatevarprop1:Intprivatevarprop2:Boolprivatevarprop3:Stringinit(_builderBlock:(SomeBuilder)->Void){letsomeBuilder=SomeBuilder()builderBlock(someBuilder)//输入参数的无转义使用prop1=someBuilder.prop1prop2=someBuilder.prop2prop3=someBuilder.prop3}}//当使用letsomeOjb=SomeObj{builderinbuilder.prop1=15builder.prop2=falsebuilder.prop3="haha"}2.自动配对操作经常用到,我们开发在此过程中,你会遇到必须配对才能正常工作的API,例如打开和关闭文件、进入编辑模式和退出编辑模式等。虽然swift语言给了我们defer这样的语法糖来防止人们忘记配对操作,但是代码看起来还是不太顺眼funcupdateTableView1(){self.section:0)],with:.fade)self.tableView.deleteRows(at:[IndexPath(row:5,section:0)],with:.fade)self.tableView.endUpdates()//容易遗漏或上面发生异常}funcupdateTableView2(){self.tableView.beginUpdates()defer{self.tableView.endUpdates()}self.tableView.insertRows(at:[IndexPath(row:2,section:0)],with:。fade)self.tableView.deleteRows(at:[IndexPath(row:5,section:0)],with:.fade)}使用noescape作为参数,我们可以封装要操作的流程,让上层看起来更regular//ExtendUITableViewextensionUITableView{funcupdateCells(updateBlock:(UITableView)->Void){beginUpdates()defer{endUpdates()}updateBlock(self)}}funcupdateTableView(){//使用self.tableView.updateCells时{(tableView)intableView.insertRows(at:[IndexPath(row:2,section:0)],with:.fade)tableView.deleteRows(at:[IndexPath(row:5,section:0)],with:.fade)}}function这里简单介绍一下作为入参。让我们看一下作为返回值的函数。函数作为返回值在你的日常开发中,肯定很少有使用函数作为返回值的情况。但是,如果能够简单地使用它,它会让代码一下子变得更加简洁。首先,没有争议的是,我们有很多API都需要函数作为入参,无论是上一节提到的escaping入参,还是noescape入参。所以很多时候,你写的代码会有很高的重复率,比如:letarray=[1,3,55,47,92,77,801]letarray1=array.filter{$0>3*3}letarray2=array.filter{$0>4*4}letarray3=array.filter{$0>2*2}letarray4=array.filter{$0>5*5}一段代码,从数组中求某个数的平方,如果是没有封装,看起来应该是这样的。为了简单起见,通常封装成如下两种形式:value:3)letarray2=biggerThanPowWith(array:array,value:4)letarray3=biggerThanPowWith(array:array,value:2)letarray4=biggerThanPowWith(array:array,value:5)如果使用higher的返回值函数-order函数,可以做成这样一个高级函数://一个函数funcbiggerThanPow2With(value:Int)->(Int)->Bool{return{$0>value*value}}letarray1=array.filter那个返回(Int)->Bool(biggerThanPow2With(value:3))letarray2=array.filter(biggerThanPow2With(value:4))letarray3=array.filter(biggerThanPow2With(value:2))letarray4=array.filter(biggerThanPow2With(value:5))你会话虽如此,两者之间没有区别。所以这里需要说一下使用高阶返回函数的一些好处1.不需要包装函数,也不需要打开原来的类。和上面那个简单的包一样,其实就是一个以数组为入参的包装函数。这样写代码和看代码的时候有点不适应。毕竟,每个人都喜欢OOP。如果要OOP,就要扩展原来的类。一种方法是添加扩展,或者直接向类中添加新方法。2.阅读代码时,一目了然。在使用简单包的时候,看代码的人并不知道内部使用了过滤函数。你必须查看源代码才能知道。但是在使用高阶函数的时候,马上就知道用到了系统库的过滤器。3.更容易复用这也是最关键的一点。细粒度的高阶函数可以更方便地复用。比如我们知道Set还有一个filter方法,复用是这样的:letset=Set
