In-depth understanding of functions in Go language [closure] 11

Article directory


Closure

  A closure is a function that references a free variable that will exist with the function even after leaving the environment in which it was created. The closure copies the pointer to the original object.

The Go language supports closures. Here is a brief introduction to how closures are implemented in the Go language.

package main

import (
    "fmt"
)

func a() func() int {
    
    
    i := 0
    b := func() int {
    
    
        i++
        fmt.Println(i)
        return i
    }
    return b
}

func main() {
    
    
    c := a()
    c()
    c()
    c()

    a() //不会输出i
}

Output result:

    1
    2
    3

The closure copies the original object pointer, which easily explains the delayed reference phenomenon.

package main

import "fmt"

func test() func() {
    
    
    x := 100
    fmt.Printf("x (%p) = %d\n", &x, x)

    return func() {
    
    
        fmt.Printf("x (%p) = %d\n", &x, x)
    }
}

func main() {
    
    
    f := test()
    f()
}

output:

    x (0xc42007c008) = 100
    x (0xc42007c008) = 100

At the assembly layer, what test actually returns is the FuncVal object, which contains the address of the anonymous function and the pointer to the closure object. When calling an anonymous function, just pass the object in a register.

    FuncVal { func_address, closure_var_pointer ... }

external reference function parameter local variable

package main

import "fmt"

// 外部引用函数参数局部变量
func add(base int) func(int) int {
    
    
    return func(i int) int {
    
    
        base += i
        return base
    }
}

func main() {
    
    
    tmp1 := add(10)
    fmt.Println(tmp1(1), tmp1(2))
    // 此时tmp1和tmp2不是一个实体了
    tmp2 := add(100)
    fmt.Println(tmp2(1), tmp2(2))
}

returns 2 closures

package main

import "fmt"

// 返回2个函数类型的返回值
func test01(base int) (func(int) int, func(int) int) {
    
    
    // 定义2个函数,并返回
    // 相加
    add := func(i int) int {
    
    
        base += i
        return base
    }
    // 相减
    sub := func(i int) int {
    
    
        base -= i
        return base
    }
    // 返回
    return add, sub
}

func main() {
    
    
    f1, f2 := test01(10)
    // base一直是没有消
    fmt.Println(f1(1), f2(2))
    // 此时base是9
    fmt.Println(f1(3), f2(4))
}
package main

import "fmt"

//闭包(Closure)是引用了自由变量的函数。自由变量将和函数一同存在,即使已经离开了创造它的环境。
func sub() func() {
    
    
	i := 10
	fmt.Printf("%p\n", &i)
	b := func() {
    
    
		fmt.Printf("i addr %p\n", &i) //闭包复制的是原对象的指针
		i--                           //b函数内部引用了变量i
		fmt.Println(i)
	}
	return b //返回了b函数,变量i和b函数将一起存在,即使已经离开函数sub()
}

// 外部引用函数参数局部变量
func add(base int) func(int) int {
    
    
	return func(i int) int {
    
    
		fmt.Printf("base addr %p\n", &base)
		base += i
		return base
	}
}

func main() {
    
    
	b := sub() // 输出 0xc000180a0
	b()        // 输出 i addr 0xc000180a0 /n 9
	b()        // 输出 i addr 0xc000180a0 /n 8
	fmt.Println()

	tmp1 := add(10)
	fmt.Println(tmp1(1), tmp1(2)) //11,13
	// 此时tmp1和tmp2不是一个实体了
	tmp2 := add(100)
	fmt.Println(tmp2(1), tmp2(2)) //101,103
}

Guess you like

Origin blog.csdn.net/m0_52896752/article/details/130144464