深入理解Go语言中的函数【闭包】11

文章目录


闭包

  闭包(Closure)是引用了自由变量的函数,自由变量将和函数一同存在,即使已经离开了创造它的环境。闭包复制的是原对象的指针。

Go语言是支持闭包的,这里只是简单地讲一下在Go语言中闭包是如何实现的。

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
}

输出结果:

    1
    2
    3

闭包复制的是原对象指针,这就很容易解释延迟引用现象。

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()
}

输出:

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

在汇编层 ,test 实际返回的是 FuncVal 对象,其中包含了匿名函数地址、闭包对象指针。当调 匿名函数时,只需以某个寄存器传递该对象即可。

    FuncVal { func_address, closure_var_pointer ... }

外部引用函数参数局部变量

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))
}

返回2个闭包

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
}

猜你喜欢

转载自blog.csdn.net/m0_52896752/article/details/130144464