Go closure variable scope

前端 未结 3 2098
既然无缘
既然无缘 2021-02-15 16:25

I\'m reading \'CreateSpace An Introduction to Programming in Go 2012\'

and on page 86 I found this evil magic

func makeEvenGenerator() func() uint {
             


        
3条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-02-15 17:15

    For the sake of clarity, I'll assign names to both functions:

    func makeEvenGenerator() func() uint { // call this "the factory"
        i := uint(0)
    
        return func() (ret uint) { // call this "the closure"
            ret = i
            i += 2
            return
        }
    }
    

    The factory returns the closure – functions are first class citizens in Go i.e. they can be right-hand expressions, for example:

    f := func() { fmt.Println("f was called"); }
    
    f() // prints "f was called"
    

    In your code, the closure wraps over the context of the factory, this is called lexical scoping. This is why the variable i is available inside the closure, not as a copy but as a reference to i itself.

    The closure uses a named return value called ret. What this means is that inside the closure you'll have implicitly declared ret and at the point of return, whatever value ret has will be returned.

    This line:

    ret = i
    

    will assign the current value of i to ref. It will not change i. However, this line:

    i += 2
    

    will change the value of i for the next time the closure is called.


    Here you'll find a little closure example I wrote together for you. It's not extremely useful but illustrates the scope, purpose and use of closures pretty well in my opinion:

    package main
    
    import "fmt"
    
    func makeIterator(s []string) func() func() string {
        i := 0
        return func() func() string {
            if i == len(s) {
                return nil
            }
            j := i
            i++
            return func() string {
                return s[j]
            }
        }
    }
    
    func main() {
    
        i := makeIterator([]string{"hello", "world", "this", "is", "dog"})
    
        for c := i(); c != nil; c = i() {
            fmt.Println(c())
        }
    
    }
    

提交回复
热议问题