个人技术分享

  defer延迟调用机制

是什么?为什么?

延迟调用是函数return正常结束后或者painc异常结束前会执行的一些操作。

再申请资源的时候延迟调用,防止忘记资源释放,数据库、文件、锁等资源释放。

延迟调用的顺序?

会按先进后出的顺序执行。

defer的值什么时候传递的?对外部变量如何引用?

defer定义时值就传递给defer了。

defer定义时对外部变量引用有两种方式:函数参数、闭包引用  

func main() {
	n := 3
	defer fmt.Println(n)
	n = 5
}
type number int

func (n number) print()   { fmt.Println(n) }
func (n *number) pprint() { fmt.Println(*n) }
func main() {
	var n number
	defer n.print()
	n = 3
}

/*
	defer n.print()
	defer n.pprint()
	defer func() { n.print() }()
	defer func() { n.pprint() }()
*/

defer_使用

func main() {
	defer fmt.Println("函数退出前执行")
}

defer_特性多个defer的执行顺序

func main() {
	defer fmt.Println("顺序 1")
	defer fmt.Println("顺序 2")
	defer fmt.Println("顺序 3")
}

//结果
/*
顺序 3
顺序 2
顺序 1
 */

 defer_return xxx 的注意事项

执行顺序
return ***
defer
return 

func f() int {
	r := 5
	defer func() { r += 5 }()
	return r
}
func main() {
	fmt.Println(f())
}

func f() (r int) {
	t := 5
	defer func() { t += 5 }()
	return t
}
func main() {
	fmt.Println(f())
}
func f() (r int) {
	r = 5
	defer func() { r += 5 }()
	return
}
func main() {
	fmt.Println(f())
}

defer_应用释放资源

打开文件

func main() {
	file, err := os.Open("example.txt") //打开文件
	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}
	defer file.Close() // 在函数结束前确保文件被关闭

	//对文件的操作
	//...

	// 这里不需要显式关闭文件,defer 会在函数结束时调用 file.Close()
}

http请求

func main() {
	// 发起 HTTP GET 请求
	resp, err := http.Get("https://jsonplaceholder.typicode.com/posts/1")
	if err != nil {
		fmt.Println("Error fetching data:", err)
		return
	}
	defer resp.Body.Close() // 确保在函数结束时关闭 HTTP 响应体

	// 读取响应的内容
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return
	}

	fmt.Println("Response:", string(body))
}

defer_应用事务回滚

func performDatabaseOperation() error {
	db, err := sql.Open("mysql", "username:password@tcp(localhost:3306)/dbname")
	if err != nil {
		return err
	}
	defer db.Close() // 确保在函数结束时关闭数据库连接

	// 开始数据库事务
	tx, err := db.Begin()
	if err != nil {
		return err
	}
	defer func() {
		if p := recover(); p != nil {
			fmt.Println("Recovering from panic:", p)
			tx.Rollback() // 如果出现 panic,回滚事务
			panic(p)      // 继续传播 panic
		}
	}()

	// 在事务中执行一些操作
	_, err = tx.Exec("INSERT INTO table_name (column_name) VALUES (?)", "some value")
	if err != nil {
		tx.Rollback() // 发生错误时回滚事务
		return err
	}

	// 在函数结束时提交事务
	defer tx.Commit()

	// 模拟某些可能触发 panic 的操作
	// panic("something went wrong")

	return nil
}