golang 闭包笔记

Posted by Jason on Tuesday, September 3, 2019

TOC

闭包

初遇闭包

func A() {
     ....
     func() {
        rw.RLock() 
        defer rw.UnRLock() 
        ....
     }()
     ....
     
}()

该函数是k8s中源码部分函数,在阅读源码时奇怪作者为什么会使用闭包?

  • 不假思索觉得是因为:因为该部分代码只想调用一次,如果提取出来其他人会调用,所以用闭包+.+! 但是再仔细一想,不让别人调用干嘛要提出一个函数呢。。。
  • 观察该函数中defer关键字后,进一步思考:如果没有闭包,那这个函数体中执行的代码会怎样?defer的范围会扩大!
  • 仔细思考后,在这里使用闭包考虑主要是想降低锁的粒度。

深入思考

闭包中变量的使用场景:

type T struct {
	v int
}

func (t *T) Incr(wg *sync.WaitGroup) {
	defer wg.Done()
	t.v++
}

func (t *T) Print() {
	time.Sleep(time.Second)
	fmt.Println(t.v)
}

func main() {
	var wg sync.WaitGroup
	ts := make(map[int]T)
	for i := 0; i < 10; i++ {
		ts[i] = T{i}
		wg.Add(1)
	}

	for _, v := range ts {
		go v.Incr(v)
	}
	wg.Wait()

	for _, v := range ts {
		go v.Print()
	}

	time.Sleep(2 * time.Second)
}

上面输出结果:99999999999 或者 77777777777

  1. 在 range 结构块中变量 v 是临时变量,并且只在进入结构块过程中被初始化一次;
  2. 闭包调用 Incr,每次调用的是统一变量的函数,并且在每次循环中被重新赋值;
func testFunc() {

    c := make(chan int)
    i := 9
    go func() {
        <- c
        time.Sleep(time.Second)
	print("closure", i)
	i += 100
        c <- 1
    }

    i += 100
    <- i
    print("main", i)
    close(c)
}

上面函数输出结果:closure 109 main 209

「真诚赞赏,手留余香」

Jason Blog

真诚赞赏,手留余香

使用微信扫描二维码完成支付


comments powered by Disqus