高阶函数

在Swift中,函数可做为“一等公民”的存在,也就意味着,我们可以和使用 int 以及 String 一样,将函数当做 参数、值、类型来使用。

其中,将函数当作一个参数和值来使用可见下:

 typealias  addTwoInts = (Int,Int)->(Int)  

    var funcType = addTwoInts.self
func aAddb(a:Int,b:Int) -> Int {
return a+b
} func addFunc(_ add:addTwoInts,_ a:Int,_ b:Int) -> Int {
return add(a,b)
}
//调用
self.addFunc(aAddb, , ) // print --> 11

调用函数 “ self.addFunc(aAddb, 5, 6) ” 时候,aAddb就是一个典型的“值”, 尽管它实际上是一个函数。 与此同时, 它还做为addFunc的参数来使用。

虽然这看起来多此一举,但实际这恰恰体现了高阶函数的特点,牺牲一点点代码的简短,将重点体现在逻辑的清晰上。

一、一个高阶函数的例子

我更喜欢叫下面的这个函数为高阶函数:

     var names:[String] = ["","","","",""]  //一个包含字符串的数组
names = names.sorted { (s1, s2) -> Bool in return s1<s2 }
print(names) -----> ["248", "42", "61", "8", "95"]

这是一个排序函数。不要在意结果并没有按照数字的大小排序,那是因为这是字符串排序,规则将按照首个字母的asc值进行比较。

先看看这个函数的原型:

    public func sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> [Element]

这个函数显然是将一个  (Element, Element) -> Bool 类型的函数做为他的参数

一眼看过去,并不是那么好理解,来看下其内部的实现大概是这样的:

extension Array{

    typealias  IncreasingOrder = (String,String) -> Bool

    mutating func mySorted(_ increasingOrder:IncreasingOrder) -> [String] {
var newString:[String] = [String]() // 假设这里采用简单选择排序
for n in ..<self.count{
var tamper:String = self[n] as! String
for i in n+..<self.count { //
var next:String = self[i] as! String
guard !increasingOrder(tamper,next) else {
continue
}
swap(&tamper, &next)
swap(&self[n], &self[i])
}
newString.append(tamper)
}
return newString
}
}

调用:

names = ["","","","",""]
names = names.mySorted { (s1, s2) -> Bool in
return s1<s2
}
print(names) -----> ["248", "42", "61", "8", "95"]

这里为了简便, 直接将Element替换成了String,针对String 类型来说,这个函数的功能和系统的Sotred的功能是一样的。 如果需要支持更多的类型,可能要使用到泛型,甚至是where的可选绑定。其实系统的排序已经实现可选绑定式的排序了:重载了sorted函数,根据Element的不同类型,推断是否需要进行可选绑定动作。

通过这个例子,可以看到,所谓的高阶函数,其实就是将一个函数做为另一个函数的参数的语法。这个语法的基础是Swift中的特性:函数的一等公民性质。

我们可以通过这种类型的语法,将类似的函数的内部代码实现隐藏,只根据参数函数的值定义如何执行内部代码。这中方式实现的代码的灵活度将大大的提高。这为在Swift 中写出使用一个函数替代多个同质化的函数提供了一种手段。 当然,做到这种效果可能还需要使用泛型编程。

函数嵌套

大部分情况下,遇到的所有功能都是全局函数,它们在全局范围内定义。如果在函数局部定义一个函数,则称为嵌套函数。

默认情况下,嵌套函数从外部世界隐藏,但在局部仍然可以正常低调用。一个闭包的函数也可以返回一个嵌套函数,以允许在其他范围内使用嵌套函数。

func chooseStepFunction(backward: Bool) -> (Int) -> Int {    //全局函数
func stepForward(input: Int) -> Int { return input + } //嵌套函数 1
func stepBackward(input: Int) -> Int { return input - } //嵌套函数 2
return backward ? stepBackward : stepForward //返回一个函数
}

调用:

var currentValue = -
let moveNearerToZero = chooseStepFunction(backward: currentValue > )
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != {
print("\(currentValue)... ") ----> // -4... // -3...// -2...// -1...
 currentValue = moveNearerToZero(currentValue) } print("zero!") // zero!

嵌套函数的本质是返回一个函数,之前所说的将函数当作参数基于同一个特性 -- 函数是swift的 一等公民。

同样的道理,一个基本类型的既然能够做为局部的变量来存在,函数为什么不行呢? 当然可以。这就是局部函数的由来,看来还是基于一等公民的身份啊。 函数嵌套将遵守与基本类型一样的原则,局部的函数,职能够在局部去访问,在外部是没有效果的。

如果我们将嵌套的函数匿名的话,也即是我们下面的这种形式:

  typealias  adds = (Int)->(Int)
func add(_ c:Int) -> adds {
return { a in
return a + c
}
}

调用:

let addStart = self.add()
let addTwo = addStart()
let addFive = addStart()
print(addTwo) -----> 2
print(addFive) -----> 5

在add函数中,定义了一个起始的数值: 0,返回一个adds类型的函数。 之后我们可以通过给adds类型的实例 addTwo和addFive传递相应的参数即可实现多个函数的套用。

比如,如果我们在做一个以一个起始值做为加减的时候,这中用法就灵活很多,比如,如果我需要以 10做为初始值:

let add = self.add()
let addTwo = add()
let addFive = add()
print(addTwo) ==> 12
print(addFive) --> 15

add已经是另一个函数了。

而实际上,这就函数嵌套的另一种使用,这有很多的叫法 ,我更愿意叫它 -- 柯里化。

柯里化

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的。

在一般函数中,并不能轻易做到柯里化,可能需要借助其他的方案,比如,将多个参数使用替换成一个struct或者class。

然而高阶函数和嵌套函数却可以很轻易的做到,并保证代码的逻辑清晰。然而为什么要使用柯里化,可以阅读这个文章。 私人觉得,柯里化的优势是去同质化的代码 以及 注重函数的实现减少参数的干扰,简洁提升逻辑。上面的例子刚好解释了柯里化的使用。

Swift 中的高阶函数和函数嵌套的更多相关文章

  1. Python 函数式编程 & Python中的高阶函数map reduce filter 和sorted

    1. 函数式编程 1)概念 函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念.wiki 我们知道,对象是面向对象的第一型,那么函数式编程也是一样,函数是函数 ...

  2. Python中的高阶函数与匿名函数

    Python中的高阶函数与匿名函数 高阶函数 高阶函数就是把函数当做参数传递的一种函数.其与C#中的委托有点相似,个人认为. def add(x,y,f): return f( x)+ f( y) p ...

  3. JS中的高阶函数

    JS中的高阶函数 高阶函数是指以函数作为参数的函数,并且可以将函数作为结果返回的函数. 1. 高阶函数 接受一个或多个函数作为输入 输出一个函数 至少满足以上一个条件的函数 在js的内置对象中同样存在 ...

  4. Java中的函数式编程(五)Java集合框架中的高阶函数

    写在前面 随着Java 8引入了函数式接口和lambda表达式,Java 8中的集合框架(Java Collections Framework, JCF)也增加相应的接口以适应函数式编程.   本文的 ...

  5. React中的高阶组件,无状态组件,PureComponent

    1. 高阶组件 React中的高阶组件是一个函数,不是一个组件. 函数的入参有一个React组件和一些参数,返回值是一个包装后的React组件.相当于将输入的React组件进行了一些增强.React的 ...

  6. React中的高阶组件

    高阶组件(HOC, High-Order Component)是React中用于重组组件逻辑的高级技术,是一种编程模式而不是React的api. 直观来讲,高阶组件是以某一组件作为参数返回一个新组件的 ...

  7. ES6中的高阶函数:如同 a => b => c 一样简单

    作者:Sequoia McDowell 2016年01月16日 ES6来啦!随着越来越多的代码库和思潮引领者开始在他们的代码中使用ES6,以往被认为是"仅需了解"的ES6特性变成了 ...

  8. JavaScript中的高阶函数

    之前写的<JavaScript学习手册>,客户跟我说有些内容不适合初学者,让我删了,感觉挺可惜的,拿到这里和大家分享. JavaScript中的一切都是对象,这句话同样适用于函数.函数对象 ...

  9. javascript中的高阶函数, 和 类定义Function, 和apply的使用

    参考: http://www.cnblogs.com/delin/archive/2010/06/17/1759695.html js中的类, 也是用function关键字来定义的: function ...

随机推荐

  1. Nginx TCP代理

    nginx 在1.9.0 版本发布以前如果要想做到基于TCP的代理及负载均衡需要通过打名为nginx_tcp_proxy_module的第三方patch来实现,该模块的代码托管在github上 网址: ...

  2. 翻翻git之---闪烁动画的TextView RevealTextView

    转载请注明出处:王亟亟的大牛之路 今天没有P1啦!. 对换工作有想法的.能够找昨天的P1.哈哈 地址:http://blog.csdn.net/ddwhan0123/article/details/5 ...

  3. [React Intl] Install and Configure the Entry Point of react-intl

    We’ll install react-intl, then add it to the mounting point of our React app. Then, we’ll use react- ...

  4. POJ 2886 Who Gets the Most Candies?(线段树&#183;约瑟夫环)

    题意  n个人顺时针围成一圈玩约瑟夫游戏  每一个人手上有一个数val[i]   開始第k个人出队  若val[k] < 0 下一个出队的为在剩余的人中向右数 -val[k]个人   val[k ...

  5. decode与case when

    语法 decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) select * from reglike; ,),'aaa','yes','no') decode from ...

  6. SourceInsight打开的工程中中文字体显示乱码的问题

    1.在ubuntu下进入文件所在目录执行指令“file *”来查看文件的编码方式,sourceinsight有些版本只支持GB2312和ascil码,所以需要编码转换: 2.在ubuntu下可以通过i ...

  7. mysql常见故障诊断

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010230971/article/details/80335578 作为故障预警,应该尽量把问题扼 ...

  8. [Docker] Create Docker Volumes for Persistent Storage

    Docker containers are stateless by default. In order to persist filesystem changes, you must use doc ...

  9. POJ 1887 Testing the CATCHER(LIS的反面 最大递减子序列)

    Language: Default Testing the CATCHER Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 1 ...

  10. Linux下多线程查看工具(pstree、ps、pstack),linux命令之-pstree使用说明, linux 查看线程状态。 不指定

    0.最常用 pstree:[root@iZ25dcp92ckZ temp]# pstree -a|grep multe  |       |   `-multepoolser  |       |   ...