Closure

Reason is the light and the light of life.

Jerry Su May 24, 2019 1 mins

什么是闭包?

引用至少一个自由变量的函数称为闭包。

闭包是一个函数,可纯函数或非纯函数,可有名字或匿名,但重要的是它是一个函数。 为何称其为闭包,它与函数最重要的区别是:引用自由变量

// p相对于getHike,是其自由变量。getHike函数没有局部变量和列表参数p。
var p =10
def getHike(salary:Double) = salary * p/100
getHike(5000)

如果自由变量值发生变化会怎样?

执行闭包时,它采用最新的自由变量的值。

    var p =10
    def getHike(salary:Double) = salary * p/100
    getHike(5000)
    //res1: Double = 500.0
    p=20
    getHike(5000)
    //res2: Double = 1000.0    

闭包是否为纯函数:取决于自由变量的类型var和val

如果闭包修改了自由变量的值会怎样?

如果闭包修改了自由变量,则更改在闭包外部可见。

    var p =10
    def getHike(salary:Double) = { 
            p=p*2
            salary * p/100
        }
    println(p)
    //10
    getHike(5000)
    //res8: Double = 1000.0
    println(p)
    //20    

为什么需要闭包,有什么优势?

函数式编程,函数可以最为参数传递和返回,与面向对象类似。

对于某些例子,对象更灵活,因为对象携带方法和数据元素(状态)。然而,函数是唯一的,因为它没有任何数据元素(状态)。

所以,如果我们需要传递一堆状态和一个函数,那么使用:闭包自由变量

    val l = (1001 to 1005).toList
    l.map(getHike)     

    def getHike =  {
        //Load employee and their current salary
        val e:Map[Int,Double] = Map(1001->35000.00, 
                                1002->43000.00, 
                                1003->28000.00, 
                                1004->54000.00, 
                                1005->17000.00)
        // Some logic to derive percentage for each employee
        val p:Map[Int,Double]  = Map(1001 -> 10.00, 
                                1002->12.00, 
                                1003->7.50, 
                                1004->6.80, 
                                1005->20.00)
        (empID:Int) => (empID, e(empID) * p(empID) /100.00) // 返回一个匿名函数,即闭包
        }        

    val f = getHike
    f: Int => (Int, Double) = <function1>
    //Get Hike for an employee
    f(1001)
    //res10: (Int, Double) = (1001,3500.0)
    //Get Hike for a non existant employee
    f(1006)
    //java.util.NoSuchElementException: key not found: 1006     

从最后一行返回的匿名函数是一个闭包。它使用两个自由变量e和p。

当我们从getHike返回它时,它带有e和p的状态。

所以,f包含它的数据。闭包就像面向对象世界里传递的一个对象!

它节省了大量复杂且不必要的代码,并简化了解决方案。


Read more:

Related posts: