defer、go、闭包

461 阅读1分钟

一、defer和go后面的函数

先来看defer

package main

import "fmt"

func main() {
    var i int = 1

    defer fmt.Println("result =>",func() int { return i * 2 }())
    i++
}

输出结果:

    result => 2
看这个代码会疑惑结果为何不是result=>4 呢??
原因是 调用任何一个函数前都要先对函数的参数进行求值,之后再进入函数体,只不过defer将进入函数执行的过程推迟到defer的调用方退出之前了

二、go

package main

import (
     "fmt"
    "time"
)

func main() {
    var i int = 1

    go fmt.Println("result =>",func() int { return i * 2 }())
    i++
    time.Sleep(3*time.Second)
}

输出结果:

      result => 2

所以,无论是go关键字还是defer关键字,在代码执行到它们时, 编译器都要为它们后面的函数准备好函数调用的参数堆栈,要确定的参数值和参数型大小。这样一来就得去求值:对它们后面的函数的参数进行 求值。

二、闭包函数

package main

import "fmt"

func main() {
	/*
	无参闭包
	执行函数体是用外部的引用
	*/
	var i int = 1

	defer func() {
		fmt.Println("result0 =>", func() int { return i * 2 }())//用的是i的引用
	}()
	i++
	/*
	有参闭包
	先计算此时函数的参数列表,也是引用,但是 是此时的引用
	执行函数体时用直接用当时计算出来的参数
	*/
	var ii int = 1
	defer func(ii int){//此时计算出ii得1
		fmt.Println("result1 =>", func() int { return ii * 2 }())//用的是此时外部的ii的值,与defer fmt.Println("result =>",func() int { return i * 2 }())等价
	}(ii)
	ii++
}

输出结果:

      result1 => 2
      result0 => 4

无参闭包

执行函数体是用外部的引用

有参闭包

先计算此时函数的参数列表,也是引用,但是,是此时的引用,执行函数体时用直接用当时计算出来的参数