defer和time

1. defer

defer是go语言中,一个特殊的关键字,用于延迟调用

什么叫延迟调用?

让函数或方法(跟在defer后的函数,我们一般称之为延迟函数)在当前函数执行完毕后但在在return或者panic之前执行。

比如:

func main() {
	x := 10
	defer func() {
		x++
        //这里打印11
		fmt.Println("我后执行:", x)
	}()
    //这里打印10
	fmt.Println("我先执行:", x)
	return
}
1
2
3
4
5
6
7
8
9
10
11

defer有以下规则:

  • 延迟函数的参数在defer语句出现时就已经确定

    func main() {
    	x := 10
    	defer func(x int) {
            //打印10 因为x传参时,值为10
    		fmt.Println("我后执行:", x)
    	}(x)
    	x++
        fmt.Println("我先执行:", x)
    	return
    }
    func deferTest() {
    	var a = 1
        //输出1
    	defer fmt.Println(a)
    	a = 2
    	return
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
  • 延迟函数执行按后进先出顺序执行, 即先出现的defer最后执行

    func main() {
    	x := 10
    	defer func(x int) {
    		fmt.Println("我后执行1:", x)
    	}(x)
    	defer func(x int) {
            //后进先出 这个会先于我后执行1执行
    		fmt.Println("我后执行2:", x)
    	}(x)
    	x++
    	fmt.Println("我先执行:", x)
    	return
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  • 延迟函数可以操作主函数的具名返回值

    func main() {
        //打印2 return i 并不是一个原子操作
        //return会分两步 1. 设值 2 return
        //所以result为先被赋值为i=1 
    	x := deferTest()
    	fmt.Println(x)
    }
    func deferTest() (result int) {
    	i := 1
    	defer func() {
    		result++
    	}()
    	return i
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • 如果 defer 执行的函数为 nil, 那么会在最终调用函数的产生 panic

    var a func()
    
    func deferTest() *int {
    	i := 1
    	defer a()
    	return &i
    }
    
    1
    2
    3
    4
    5
    6
    7

测试:

func main() {
	x := deferTest()
	fmt.Println(x)
}
func deferTest() int {
	i := 1
	defer func() {
		i++
	}()
	return i
}
1
2
3
4
5
6
7
8
9
10
11
func main() {
	x := deferTest()
	fmt.Println(*x)
}
func deferTest() *int {
	i := 1
	defer func() {
		i++
	}()
	return &i
}
1
2
3
4
5
6
7
8
9
10
11
func main() {
	x := deferTest()
	fmt.Println(*x)
}

func deferTest() *int {
	i := 1
	defer func(x *int) {
		*x++
	}(&i)
	return &i
}
1
2
3
4
5
6
7
8
9
10
11
12

注意: defer一定要定义在return或panic之前,否则会不执行。

func main() {
    //defer不会执行
    //主动调用os.Exit不会执行defer
	defer func() {
		fmt.Println("defer")
	}()
    //退出进程
	os.Exit(-1)
}
1
2
3
4
5
6
7
8
9

2. time

在编写程序时,经常会用到时间,go语言的标准库time包提供了对时间的一系列操作。

这里我们只是简单了解一下

func main() {
    //当前的时间
    t := time.Now()
    //格式化 这个是格式 2006-01-02 15:04:05
    fmt.Println(t.Format("2006-01-02 15:04:05")) //小口决,612345
}
1
2
3
4
5
6

秒值,毫秒值:

func main() {
	//当前的时间
	t := time.Now()
	//毫秒值
	milli := t.UnixMilli()
	//秒值
	sencond := t.Unix()
	fmt.Printf("毫秒值:%d, 秒值:%d \n", milli, sencond)
}
1
2
3
4
5
6
7
8
9

时间相加相减:

func main() {
	//当前的时间
	t := time.Now()
	fmt.Println(t.Format("2006-01-02 15:04:05"))
	after20s := t.Add(20 * time.Second)
	fmt.Println(after20s.Format("2006-01-02 15:04:05"))
	sub := after20s.Sub(t)
	fmt.Printf("相减时间:%v \n", sub)
}
1
2
3
4
5
6
7
8
9

休眠:

func main() {
    //阻塞当前的go程x时间,x<=0时立即 释放
	time.Sleep(2 * time.Second)
	fmt.Println("等2秒打印出来")
}
1
2
3
4
5

经过一段时间后返回:

func main() {
	ch := make(chan struct{})
	go wait(ch)
	select {
	case <-ch:
		fmt.Println("wait执行成功")
	case <-time.After(2 * time.Second):
		fmt.Println("wait等待时间已经超过2秒,超时了")
	}
}

func wait(ch chan struct{}) {
	time.Sleep(3 * time.Second)
	ch <- struct{}{}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15