10 minutes go study notes the brief closure of language understanding technology go

Closure is a mainstream programming language of general technical , and often functional programming powerful combination, this paper is to introduce the Golanguage of what is closure and how to understand closures .

If the reader for the Goclosure of language is not particularly clear , you can refer to the previous article go study notes that it only requires a clear example of what can closures .

Or you can directly ignore , because you'll recall antecedent summary , now are you ready? Go!

go-functional-programming-closure-cheer.png

Fibonacci columns see closures

Whether Gothe official website or other online tutorials to explain the closure, can always see the Fibonacci column figure, illustrates the example of a classic !

Fibonacci number ( Fibonacci sequence), also known as golden columns . Because mathematician Leonardo Fibonacci ( Leonardoda Fibonacci) to rabbit breeding as an example and introduced, it is also known as "rabbit columns", referring to such a number of columns: 1、1、2、3、5、8、13、21、34、……mathematically, fibonacci numbers listed in the following are defined in a recursive method: F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)in the field of modern physics, quasi-crystalline structure, chemistry, fibonacci sequence has a direct application for this, American mathematical Publishing a magazine with Mathematics "fibonacci Quarterly" in the name since 1963, is devoted to research in this area.

go-functional-programming-about-fib.png

According to the Baidu Encyclopedia For a description, we know Fibonacci column is shaped like 1 1 2 3 5 8 13 21 34 55an increasing number of columns from the third start, the current item is the sum of the first two .

For ease of calculation, the definition of two variables a,brepresents the first two, the initial values are set to 0,1the example:

// 0 1 1 2 3 5 8 13 21 34 55
// a b 
//   a b
a, b := 0, 1

After initializing the next round of movement, a, b = b, a+bthe result is a , b = 1 , 1, just to represent Fibonacci columns beginning.

"Snow Dream Inn technology" Imagine: If the a,binitial value of the variable is 1,1, without changing the logic , that deed Fibonacci number generated by the final column is what?

func fibonacciByNormal() {
    a, b := 0, 1

    a, b = b, a+b

    fmt.Print(a, " ")

    fmt.Println()
}

However, the above example can only generate Fibonacci number in the first number, if we need first ten columns , how?

func fibonacciByNormal() {
    a, b := 0, 1

    for i := 0; i < 10; i++ {
        a, b = b, a+b

        fmt.Print(a, " ")
    }

    fmt.Println()
}

By a specified number of cycles and then slightly modifying the above singular column code, now can be generated ten columns:

// 1 1 2 3 5 8 13 21 34 55
func TestFibonacciByNormal(t *testing.T) {
    fibonacciByNormal()
}

This approach is in contact with the front closure concept we have been the solution adopted, I believe there are some little programming experience developers can achieve, but the closure has provided another idea!

// 1 1 2 3 5 8 13 21 34 55
func fibonacci() func() int {
    a, b := 0, 1
    return func() int {
        a, b = b, a+b
        return a
    }
}

Whether ordinary function or a function closure to achieve Fibonacci column logic generator function is the same, only to realize different closures returns internal function, leave the user continues to call ordinary function is generated directly Fibonacci of number.

// 1 1 2 3 5 8 13 21 34 55 
func TestFibonacci(t *testing.T) {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Print(f(), " ")
    }
    fmt.Println()
}

For this internal function nested inside another function and the function reference such an implementation external variables, called "closure"!

"Snow Dream Inn technology": closure is a function + reference environment organic whole composition, both are indispensable, Refer to go study notes that it only requires a clear example of what can closures .

Own independent operating environment

go-functional-programming-closure-fage.jpeg

"Snow Dream Inn technology": comes with the operating environment of the closure as a movie appearances own background music of Chow, like, the music sounded, hair Gedeng field, closures occur, the environment comes!

Closure own separate operating environment , each run closure are independent of environment, as the object-oriented class and object instance of the relationship as a type closures, closure referenced object is an instance.

func autoIncrease() func() int {
    i := 0
    return func() int {
        i = i + 1
        return i
    }
}

The above-described exemplary closure is achieved increment calculator, every reference autoIncreaseclosures environment functions are independent of each other to obtain, directly on the unit test cases.

func TestAutoIncrease(t *testing.T) {
    a := autoIncrease()

    // 1 2 3
    t.Log(a(), a(), a())

    b := autoIncrease()

    // 1 2 3
    t.Log(b(), b(), b())
}

Function references aand bthe environment are independent, the equivalent of another identical counter starts counting again, and will not affect the operating results of the original counter.

"Snow Dream Inn technology": the closure is not just a function , more important is the environment from the operating results point of view, every time it is referenced closure function. Reinitialize the operating environment of this mechanism is very similar to the object-oriented classes and instances object relationship!

Immortality is a blessing or a curse

Normal function of the internal variables defined limited lifespan, after the end of the function of the system running will be destroyed, ending his brief and glorious life.

However, the closure variables referenced is not the same, as long as has been in use in the state, then the variable will " live forever " and will not be born in the function and the general variable has the same short life.

  • Old steed, high aspirations

go-functional-programming-closure-horse.jpeg

func fightWithHorse() func() int {
    horseShowTime := 0
    return func() int {
        horseShowTime++

        fmt.Printf("(%d)祖国需要我,我就提枪上马立即战斗!\n",horseShowTime)

        return horseShowTime
    }
}

func TestFightWithHorse(t *testing.T) {
    f := fightWithHorse()

    // 1 2 3
    t.Log(f(), f(), f())
}

go-functional-programming-closure-fight.png

"Snow Dream Inn technology": If users have been using function closures, the closure of free variables internal references will not be destroyed, has been in an active state , so as to obtain eternal life super powers !

  • Misfortune relied upon by Fu Fu Xi disaster by V

Everything good foundation, that the closure of the reference variable undead immortal , if you do not understand the variable immortality properties that may accidentally fall into when writing closure function scope trap , do be careful!

go-functional-programming-closure-laozi.jpg

Below an example to explain the variable binding loop closure scope traps, for example:

func countByClosureButWrong() []func() int {
    var arr []func() int
    for i := 1; i <= 3; i++ {
        arr = append(arr, func() int {
            return i
        })
    }
    return arr
}

countByClosureButWrongFree variable closure function references not only arrthe array as well as the loop variable i, the overall logic function is: function to maintain a closure internal array of functions, save the main function returns the loop variable.

func TestCountByClosure(t *testing.T) {
    // 4 4 4
    for _, c := range countByClosureButWrong() {
        t.Log(c())
    }
}

When we run the countByClosureButWrongfunction to obtain an array of functions returning a closure arr, then rangetraverse the array keywords, get function term is traversed c.

When we run c(), the desired output 1,2,3value of the loop variable, but the actual result is 4,4,4.

go-functional-programming-closure-wrong.png

The reason is still immortal variable characteristics: binding when traversing the loop variable value certainly 1,2,3, but the loop variable ibut not as dying like a normal function but has been forever, so variable references changed!

go-functional-programming-closure-wrong-explain.png

The value of the loop variable is exactly immortality original termination condition for the loop i=4, as long as the operation function closures, regardless of which of the array is the same function reference variable i, so all are 4,4,4.

Since it is a variable reference problem, then solve it is very simple, no variable references like it!

The easiest way is to use a short temporary variable n temporarily stores the value being traversed, variable references within the closure is no longer ibut a temporary variable n.

func countByClosureButWrong() []func() int {
    var arr []func() int
    for i := 1; i <= 3; i++ {
        n := i

        fmt.Printf("for i=%d n=%d \n", i,n)

        arr = append(arr, func() int {
            fmt.Printf("append i=%d n=%d\n", i, n)

            return n
        })
    }
    return arr
}

go-functional-programming-closure-wrong-fix.png

The above solution was simply to adopt temporary variable bindings value of the loop variable , rather than the original immortality variable references, but this practice is not elegant, but also continue to simplify the upgrade version.

Since it is the use of variable assignment practices, and is not a parameter passed in the value of the transfer is very similar? Then we can re-copy the value of a variable passed to the closure function by way of transfer value.

func countByClosureWithOk() []func() int {
    var arr []func() int
    for i := 1; i <= 3; i++ {
        fmt.Printf("for i=%d \n", i)

        func(n int) {
            arr = append(arr, func() int {
                fmt.Printf("append n=%d \n", n)

                return n
            })
        }(i)
    }
    return arr
}

"Snow Dream Inn technology": self-executing anonymous function by way of passing arguments i, internal functions use the variable nbinding external loop variable, looks more elegant, have forced grid!

With anonymous function passed by value transformation, we again run the test case to test the transformation results:

func TestCountByClosureWithOk(t *testing.T) {
    // 1 2 3
    for _, c := range countByClosureWithOk() {
        t.Log(c())
    }
}

Finally solved the problem correctly binding loop variable, and actual results appear the next time you expected, is not necessarily bugpossible to understand not deep, there is no proper use of closures!

Rushes to talk about the advantages and disadvantages

go-functional-programming-closure-compare.jpg

  • Analog class and object relationships, may also be implemented package , with some object-oriented capabilities

"Snow Dream Inn technology": each call closure function the environment are independent of each other, a feature similar to the relationship between object-oriented classes and instantiated objects.

  • Cache complex logic, memory resident, to avoid abuse of the global variable inviting maintenance costs.

"Snow Dream Inn technology": immortality features make the closure permanent memory reference variables can be used to cache some complex logic code is very suitable to avoid the misuse of the original global variables.

  • Implementation of closures higher costs , but also increased the difficulty of understanding .

"Snow Dream Inn technology": an ordinary function into a closure function not only to achieve certain degree of difficulty, and not easy to understand, not only requires more than a few times but also to understand the characteristics of the test closure.

  • Abuse easily take up too much memory, it can cause a memory leak .

"Snow Dream Inn technology": excessive use of closures is bound to create a reference variable has permanent memory, if there is a circular reference or not timely garbage collection may cause memory leaks.

Simple summary closures knowledge

Closures are a common technology, Golanguage support closures, mainly in Gonested anonymous functions internal support functions, but Godoes not support the normal function nesting.

Simple to understand, and the closure is an organic environment combined with the overall function, and operating environment independent reference variable and immortality are two important features of closures.

Whether analog object-oriented features, objects, etc. to implement caching or packaging applications are applications, both properties.

Finally, let us recall that runs through the Fibonacci row to end the closure of the trip!

func fibonacci() func() int {
    a, b := 0, 1
    return func() int {
        a, b = b, a+b
        return a
    }
}

This article relates to the sample code: https://github.com/snowdreams1006/learn-go/blob/master/functional/closure/closure_test.go

References and Further Reading

Snow Dream Inn technology .png

Guess you like

Origin www.cnblogs.com/snowdreams1006/p/11615286.html