defer使用细节

package main

import "fmt"

func main() {
   fmt.Println("main()开始执行")

   defer func() {
      fmt.Println("这是第1个defer")
   }()

   defer func() {
      fmt.Println("这是第2个defer")
   }()

   defer func() {
      fmt.Println("这是第3个defer")
   }()

   fmt.Println("main()执行完毕")
}

// ========== 输出过程·开始 ========== //
// main()开始执行
// main()执行完毕
// 这是第3个defer
// 这是第2个defer
// 这是第1个defer
// ========== 输出过程·结束 ========== //

// ========== 总结 ========== //
// 1、函数体中如果设置了多个defer,那么后设置的会先执行。



package main

import "fmt"

func main() {
   slice := []int{1001, 1002} // 长度为2的int切片

   array := [2]int{2001, 2002} // 长度为2的int数组

   defer func(s []int) {
      fmt.Printf("slice:%d %d \n", s[0], s[1]) // slice:1003 1004
   }(slice)

   defer func(a [2]int) {
      fmt.Printf("array:%d %d \n", a[0], a[1]) // array:2001 2002
   }(array)

   slice[0] = 1003
   slice[1] = 1004

   array[0] = 2003
   array[1] = 2004

   fmt.Println("即将执行defer操作……")
}

// ========== 输出过程·开始 ========== //
// 即将执行defer操作……
// array:2001 2002
// slice:1003 1004
// ========== 输出过程·结束 ========== //

// ========== 总结 ========== //
// 1、如果defer后面调用的匿名函数传入参数,那么形参的值恒定为设置defer那一刻的值,后续修改实参不会再影响形参。
//    以上面的array变量为例,虽然在设置defer之后又修改了array变量,但设置defer时形参a的值已经固定为{2001, 2002}了,
//    后续不管怎么修改array变量都不会再影响形参a的值。
// 2、defer后面调用的匿名函数传入切片变量似乎违背了上面的结论,其实不然,因为切片的数据结构里有指针(可查看源码),
//    程序是通过指针去访问切片元素的,所以匿名函数打印出来的是slice变量修改后的内容,这并没有和上面的结论冲突。
//    数据结构无指针:基本数据类型(int|float|bool|string)、数组、结构体(struct)
//    数据结构有指针:map、chan、切片(slice)、接口(interface)、函数(func)、指针

Copyright © 2024 码农人生. All Rights Reserved