高阶函数

在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. JS学习笔记 - fgm练习 - 鼠标移入/移出div样式改变

    思路: div的默认样式正常设置. 鼠标移入时,发生改变的样式有3个,即 边框颜色,div背景色,字体颜色. 把这三个css改变设置在一个类名下,再通过js给div动态 添加/去除这个类名,实现div ...

  2. 【习题 3-9 UVA - 10340】All in All

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 相当于让你判断s1是不是s2的子序列. for一遍就好 [代码] #include <bits/stdc++.h> us ...

  3. watchdog的正确使用方法

    关于watchdog应该有过单片机学习经历的人.都比較熟悉.但watchdog的正确使用方法,恐怕大家假设没有经历过实际产品的开发不会有深入的理解. 瑞萨RL78系列的单片机自身带有watchdog, ...

  4. 数学之路-python计算实战(7)-机器视觉-图像产生加性零均值高斯噪声

    图像产生加性零均值高斯噪声.在灰度图上加上噪声,加上噪声的方式是每一个点的灰度值加上一个噪声值.噪声值的产生方式为Box-Muller算法生成高斯噪声. 在计算机模拟中,常常须要生成正态分布的数值.最 ...

  5. 2015第30周四Java日志组件

    Java 日志 API 从功能上来说,日志 API 本身所需求的功能非常简单,只需要能够记录一段文本即可.API 的使用者在需要进行记录时,根据当前的上下文信息构造出相应的文本信息,调用 API 完成 ...

  6. 如何在移动web模仿客户端给input输入框添加自定义清除按钮

    项目有个需求就是在input输入框添加清除按钮,网上查找资料加上自己琢磨终于弄出来了. 灵感来自于 http://www.zhangxinxu.com/wordpress/?p=4077 由于项目已经 ...

  7. cmder显示UTF-8字体

    https://blog.csdn.net/x_iya/article/details/50627829 WIN+ALT+P打开配置 搜索chcp chcp 65001

  8. 2016 Java程序员的年终总结(转)

    2016 Java程序员的年终总结 技术积累 (1)代码规范 1.1.1.通常的模块分布:一般如果你要实现一个web 应用,你从后台将数据展示到前端页面,在一个比较大的公司,你少不了跟其他项目有交集( ...

  9. python开发环境设置(windows)

    python开发环境设置(windows) 1)  python2.7.3安装 在www.python.org上下载python-2.7.6.amd64.msi软件.安装完毕后设置path路径.控制面 ...

  10. GitHub项目协作基本步骤 分类: C_OHTERS 2013-09-23 21:31 690人阅读 评论(0) 收藏

    1.查找某个项目,然后Fork 2.打开GitHub For Windows,发现刚才Fork的项目 3.对着项目点击Clone,将之复制至本地 4.使用Eclipse等进行开发,如新增一个文件 5. ...