Swift 中的高阶函数和函数嵌套

高阶函数

在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, 5, 6)       //  print  -->   11     

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

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

一、一个高阶函数的例子

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

     var names:[String] = ["61","95","8","248","42"]  //一个包含字符串的数组
     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 0..<self.count{
            var tamper:String = self[n] as! String
            for i in n+1..<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 = ["61","95","8","248","42"]
  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 }     //嵌套函数 1
    func stepBackward(input: Int) -> Int { return input - 1 }    //嵌套函数 2
    return backward ? stepBackward : stepForward                 //返回一个函数
}

调用:

var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
    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(0)
let addTwo = addStart(2)
let addFive = addStart(5)
print(addTwo)         ----->   2
print(addFive)        ----->   5

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

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

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

add已经是另一个函数了。

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

柯里化

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

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

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

时间: 2024-08-14 21:06:23

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

scala中的高阶函数

高阶函数 val list =List(1,2,3,4,5,6,7,8) val newList = list.map((x:Int) => 2*x) //map表示映射list中的每一个元素的值为原来的2倍 //newList中的值为 2,4,6,8,10,12,14,16 也可直接写成 val newList = list.map(x => 2*x) 也可等价写成 val newList = list.map(2*_) map函数相当于foreach 集合Set val s = Set(1

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

1. 函数式编程 1)概念 函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念.wiki 我们知道,对象是面向对象的第一型,那么函数式编程也是一样,函数是函数式编程的第一型.在面向对象编程中,我们把对象传来传去,那在函数式编程中,我们要做的是把函数传来传去,而这个,说成术语,我们把他叫做高阶函数.飞林沙 2)特点 计算视为视为函数而非指令 纯函数式编程:不需变量,无副作用,测试简单(每次的执行结果是一样的) 支持高阶函数,代码简洁 2. python支持

python 中的高阶函数

函数名其实就是指向函数的变量 >>> abs(-1) 1 >>> abs <built-in function abs> >>> a=abs >>> a(-1) 1 高阶函数:能接收函数做变量的函数 >>> def abc(x,y,f): ... return f(x)+f(y) ... >>> abc(-2,3,abs) 5 python中的内置高阶函数 map()函数和reduce(

python中的高阶函数

高阶函数英文叫Higher-order function.什么是高阶函数?我们以实际代码为例子,一步一步深入概念. 变量可以指向函数 以Python内置的求绝对值的函数abs()为例,调用该函数用以下代码: >>> abs(-10) 10 但是,如果只写abs呢? >>> abs <built-in function abs> 可见,abs(-10)是函数调用,而abs是函数本身. 要获得函数调用结果,我们可以把结果赋值给变量: >>> x

JavaScript中的高阶函数

之前写的<JavaScript学习手册>,客户跟我说有些内容不适合初学者,让我删了,感觉挺可惜的,拿到这里和大家分享. JavaScript中的一切都是对象,这句话同样适用于函数.函数对象可以作为函数的参数. 一 函数对象作为另一个函数的参数 函数可以作为另外一个函数的参数,这里的"另外一个函数"可以返回具体的值,也可以返回一个函数.第二种情况就是函数的函数,称为高阶函数.在介绍这两种情况之前,先了解一下 call() 和 apply() 方法: call()  的使用方式

第6节 Scala中的高阶函数:1、2、3、

Scala高级特性 1.    课程目标 1.1.   目标一:深入理解高阶函数 1.2.   目标二:深入理解隐式转换 2.    高阶函数 2.1.   概念 Scala混合了面向对象和函数式的特性,我们通常将可以作为参数传递到方法中的表达式叫做函数.在函数式编程语言中,函数是“头等公民”,高阶函数包含:作为值的函数.匿名函数.闭包.柯里化等等. 2.2.   作为值的函数 可以像任何其他数据类型一样被传递和操作的函数,每当你想要给算法传入具体动作时这个特性就会变得非常有用. 定义函数时格式

Swift 烧脑体操(三) - 高阶函数

前言 Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说更加困难.不过一切都是值得的,Swift 相比 Objective-C,写出来的程序更安全.更简洁,最终能够提高我们的工作效率和质量. Swift 相关的学习资料已经很多,我想从另外一个角度来介绍它的一些特性,我把这个角度叫做「烧脑体操」.什么意思呢?就是我们专门挑一些比较费脑子的语言细节来学习.通过「烧

【Scala】高阶函数和柯里化

高阶函数 在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数: - 接受一个或多个函数作为输入 - 输出一个函数 在数学中它们也叫做算子(运算符)或泛函.微积分中的导数就是常见的例子,因为它映射一个函数到另一个函数. 高阶函数的例子 假设有一个函数对给定两个数区间中的所有整数求和: def sumInts(a: Int, b: Int): Int = if(a > b) 0 else a + sumInts(a + 1, b) 如果现在要求连续整数的平方和: def square(x:

Erlang高阶函数

对于函数式语言来说,函数也想普通的数据类型一样无处不在.函数即可以当成参数进行传递,也可以当成函数的返回值.当我第一次学习函数式编程的时候,我被这样的写法弄的头昏脑涨.下面我举例说明下(例子摘录自Learn You Some Erlang): 假如你想对一个列表中的所有值都进行加1或减1的操作,那么不熟悉函数式编程者给出的是如下的程序: -module(hhfuns). -compile(export_all). increment([]) -> []; increment([H|T]) ->