Scala编程——第六章:Scala函数式编程高级(下)

一、闭包

  • 在Scala中,你可以在任何作用域内定义函数。如在包中、类中、甚至是另一个函数或方法中。在函数体内,你可以访问到相应作用域内的任何变量(这很正常),但是当变量不在作用的时候,函数仍然可以访问到这个变量。
  • 这样一个函数称作"闭包"。闭包由代码和代码用到的非局部变量定义构成。 闭包可以让你的函数访问非局部变量。
    定义一个函数字面量:
    val addMore = (x: Int) => x + more
    
    more是一个自由变量。函数字面量本身没有给more赋值。
    x是一个绑定变量。它被定义为改函数的唯一参数。
    
    如果现在直接使用,而没有在任何作用域内定义定义more将编译出错。
    需要先定义more变量。
    
    var more = 1
    val addMore = (x: Int) => x + more
    addMore(10)   得到11
    
    在这里插入图片描述
    如果more在闭包创建后发生了改变,那么闭包中也能捕获more的改变
    在这里插入图片描述
    所以Scala的闭包捕获的是变量本身,而不是变量的引用值。创建的闭包能捕获在闭包外对more的修改,反过来一样成立:闭包对捕获的变量的修改也能在闭包外被看到。
  • 闭包引用创建的实例是在闭包被创建时活跃 , 示例:
    def makeIncrease(more: Int) = (x: Int) => x + more
    该函数每调用一次,就会创建一个新的闭包。每个闭包都会访问在他创建时活跃的变量more
    
    val inc1 = makeIncrease(1)
    val inc9999 = makeIncrease(9999)
    
    当你调用 makeIncrease(1)时,创建了一个more的绑定值为1的闭包
    当你调用 makeIncrease(9999)时,创建了一个 more的绑定值为9999的闭包
    inc1(10)   		得到11  因为Inc1这个实例创建时,闭包引用的more变量是1
    inc9999(10) 	得到10009 因为Inc9999这个实例创建时,闭包引用的more变量是9999
    
    在这里插入图片描述

二、柯里化

  • 柯里化指的是:将原来接受两个参数的函数,变成一个新的接受一个参数的函数 的过程,新的函数返回接受原有第二个参数 作为参数的函数。
  • 示例:
    mul函数接受两个参数。
    val mul = (x: Int, y: Int) => x * y
    
    mulOneAtTime函数接受一个参数,生成另一个接受单个参数的函数。
    val mulOneAtTime = (x: Int) => ((y: Int) => x * y)
    
    调用mulOneAtTime
    mulOneAtTime(6)(7)
    
    严格的将 mulOneAtTime(6) 返回的结果是一个函数: (y: Int) => 6 * y 。而这个函数被应用到7。最终得到42
     
    scala 支持如下简写形式定义柯里化函数
    
    def mulOneAtTime(x: Int)(y: Int) = x * y
    
    在这里插入图片描述
    柯里化函数的调用形式如下:
    直接调用
    mulOneAtTime(6)(7)
    或者分步调用
    val oneMul =  mulOneAtTime(6)_     _之前没有空格,是第二个参数的占位符,其结果是指向用一个函数引用。
    oneMul(7)
    
    在这里插入图片描述

三、尾递归函数

  • 函数在最后一步调用自己的函数被称为为尾递归函数。
  • Scala编译器能够检测到尾递归函数,并将它替换成跳转到函数的最开始,在跳转之前更新参数值。
  • 如果函数是尾递归的,那么并不需要支付任务额外的运行时开销。尾递归函数并不会在每次调用的时候构建一个新的栈帧,所有的调用都会在同一个栈帧中执行。
  • 非尾递归函数示例。boom函数不是尾递归的,因为它在递归之还执行了一个递增操作。
    在这里插入图片描述
  • 尾递归的优化内容参考: 【Scala】尾递归优化

四、偏函数(Partial Functions)

五 、控制抽象

  • 参考 《Scala编程》第9章 控制抽象
©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页