golang:闭包实例

闭包

概念

闭包函数:声明在一个函数中的函数,叫做闭包函数。

闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

特点

让外部访问函数内部变量成为可能;

局部变量会常驻在内存中;

可以避免使用全局变量,防止全局变量污染;

会造成内存泄漏(有一块内存空间被长期占用,而不被释放)

闭包的创建

闭包就是可以创建一个独立的环境,每个闭包里面的环境都是独立的,互不干扰。闭包会发生内存泄漏,**每次外部函数执行的时候,外部函数的引用地址不同,都会重新创建一个新的地址。**但凡是当前活动对象中又被内部子集引用的数据,那么这个时候,这个数据不删除,保留一根

闭包实例

示例一

  • 返回一个内部函数
package main

import "fmt"

//函数片段
func add(base int) func(int) int { // 1:创建一个新内存, 其地址并命名为base用来存储int变量, 然后取出a内存处存放的值,复制一份,放入base内存

	fmt.Printf("%p\n", &base)  //2:打印变量地址0xc0420080e0, 里面存储着10【它是函数拷贝传值】

	f := func(i int) int {  //3:定义一个函数,并且用f指向它[f里面存储着这个函数的地址]
	    //7、将1用i存储起来
		fmt.Printf("%p\n", &base) // 2:打印变量地址0xc0420080e0
		base += i // 取出base里面存储的值 + i里面存储的值,然后将结果放入base存储起来
		return base //将base里面存储的值返回
	}

	return f  // 4:将函数地址f返回
}



func main() {
	aa := 10
	fmt.Printf("a的地址:%p\n", &aa) //0xc0420080a8
	t1 := add(aa)                //5、将add(a)返回的函数地址用一个t1存储起来
	c := t1(1)                   //6、调用t1指向的函数,传参为1[传值],然后将返回结果用新建的内存c存储起来
	fmt.Println(c, &c)           //11 0xc0420540b0
	fmt.Println(t1(2))           // 13  t1还是指向原来开辟的空间,此时base=11, 因此11+2

	t2 := add(100) //重新开辟一个空间调用add(100),然后将返回的函数地址用一个t2存储起来,此时base为新建立的
	fmt.Println(t2(1), t2(2))
}

  • 返回多个内部函数
package main

import "fmt"

//返回加减函数,重点:内部函数时对外部变量的引用
func calc(base int) (func(int) int, func(int) int) {

	fmt.Printf("%p\n", &base)
	add := func(i int) int {
		fmt.Printf("%p\n", &base)
		base += i
		return base
	}

	sub := func(i int) int {
		fmt.Printf("%p\n", &base)
		base -= i
		return base
	}

	return add, sub
}

//由 main 函数作为程序入口点启动
func main() {
	f1, f2 := calc(11111)
	fmt.Println(f1(1), f2(1)) //执行顺序:f1 f2 println
}

示例二

涉及 goroutine 时的情况,程序片段如下所示:

package main

import (
	"fmt"
	"time"
)

//由 main 函数作为程序入口点启动
func main() {

	for i:=0; i<5; i++ {
		go func(){
			fmt.Println(i) //i变量值也是引用.创建5个线程执行函数, for循环执行过程中可能执行完的时候,线程刚好处于i的某个值。
		}()

	}
	time.Sleep(time.Second * 1)
}

每次程序的运行结果都是不一样的
在这里插入图片描述
代码改进:

package main

import (
	"fmt"
	"time"
)

func main() {

	ch := make(chan int, 1)

	for i:=0; i<5; i++ {
		go func(){
			ch <- 1
			fmt.Println(i)
		}()

		<- ch
	}
	time.Sleep(time.Second * 1)
}

会阻塞等待:0-4值一定有
在这里插入图片描述
参考:https://blog.csdn.net/li_101357/article/details/80196650

实例三:

package main

import "fmt"

func funA() func(){
	var a = 10;
	return func (){
		fmt.Println(a); // 打印处a存储的值
	}
}


func main() {
	var b = funA() //funA()返回一个函数地址,执行一个函数,并用b保存这个地址,此时b指向这个函数
	b() // 调用b指向的函数
}

示例四:全局变量VS闭包函数

package main

import "fmt"

func Outer() func(){
	var i = 0;
	return func() {
		i++;
		fmt.Println(i)
	}
}

func main(){
	var c = Outer()
	c()
	c()
	c()

	var d = Outer()
	d()
	d()
	d()
}

// 1 2 3 1 2 3 
  • 全局函数
package main

import "fmt"

var i = 0;


func Outer() func(){

	return func() {
		i++;
		fmt.Println(i)
	}
}

func main(){
	var c = Outer()
	c()
	c()
	c()

	var d = Outer()
	d()
	d()
	d()
}
// 1 2 3 4 5 6 

实例六

package main

import "fmt"

func Outer() func() int{
	var i = 0;
	return func() int{
		 i++;
		 return i;
	}
}

func main(){
	c := Outer() // 返回一个函数
	fmt.Println(c()) //1 调用内部函数,并且拷贝i的值,返回
	fmt.Println(c()) //2 调用内部函数,并且拷贝i的值,返回

	d := c // c里面存储着函数地址,c将存储的函数地址放入d中,此时d和c指向同一个函数
	fmt.Println(d()) //3 调用内部函数,并且拷贝i的值,返回
	fmt.Println(d()) //4 调用内部函数,并且拷贝i的值,返回

	e := Outer() // 新开辟一个内存,用来调用函数。 e存储着这个内存的地址
	fmt.Println(e()) //1 调用内部函数,并且拷贝i的值,返回
	fmt.Println(e()) //2 调用内部函数,并且拷贝i的值,返回

	fmt.Println(Outer()) //0x496a30
	fmt.Println(Outer()()) //1
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值