Bài học theo mô-đun (5/5)
`defer`: đảm bảo dọn dẹp
defer trì hoãn việc thực hiện cuộc gọi cho đến khi có chức năng kèm theo
trả về. Nó chạy ngay cả khi hàm thoát do hoảng loạn. Nhiều defer
trong cùng một chức năng, thực hiện theo thứ tự LIFO (Vào sau, Xuất trước).
Đó là cơ chế đặc trưng của việc dọn dẹp tài nguyên: đóng các tập tin, mở khóa mutexes, giải phóng kết nối, khôi phục trạng thái.
Cú pháp và trường hợp sử dụng chuẩn
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // chiamata SEMPRE all'uscita della funzione
// ... usa f liberamente ...
return nilĐiển hình: f.Close(), mu.Unlock(), db.Close(), tx.Rollback(),
recover().
Các đối số được đánh giá ngay lập tức, việc thực thi bị hoãn lại
Khi bạn viết defer foo(x), x được đánh giá tại thời điểm
defer, không phải lúc thực hiện:
x := 10
defer fmt.Println(x) // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"Lệnh LIFO
Trì hoãn xếp chồng lên nhau và thực thi bắt đầu với cái gần đây nhất:
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1Điều này phù hợp với ngữ nghĩa tài nguyên: cái được mở cuối cùng là cái đầu tiên phải đóng cửa.
defer + recover: xử lý sự hoảng loạn
defer là cách duy nhất để chặn panic:
func safe() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recuperato:", r)
}
}()
panic("boom")
}Cạm bẫy: defer trong một vòng lặp
Đặt defer f.Close() vào một vòng lặp sẽ tích lũy thời gian trì hoãn **cho đến khi kết thúc
hàm **, không phải của mỗi lần lặp. Trong một vòng lặp dài, bạn mở nhiều tập tin
và chỉ đóng chúng khi chức năng thoát: nguy cơ rò rỉ bộ mô tả tệp.
// MALE: defer accumulati
for _, path := range paths {
f, _ := os.Open(path)
defer f.Close() // chiude TUTTI alla fine della funzione esterna
// ...
}
// MEGLIO: estrai in una funzione
for _, path := range paths {
elabora(path) // ogni chiamata ha il proprio scope di defer
}Hãy thử nó
In 'inizio', sau đó in 'fine' bằng defer, sau đó in 'mezzo'. Đầu ra phải là: inizio/mezzo/fine.
Hiển thị gợi ý
Trì hoãn chạy khi main() sắp quay trở lại.
Giải pháp khả dụng sau 3 lần thử
Viết ba số trì hoãn liên tiếp in 1, 2 và 3 theo thứ tự đó trong mã. Đầu ra sẽ là 3/2/1 (LIFO).
Hiển thị gợi ý
Ba lần trì hoãn theo trình tự; hãy nhớ rằng họ thực hiện theo thứ tự ngược lại.
Giải pháp khả dụng sau 3 lần thử
Cái này in cái gì? (lưu ý: đối số trì hoãn được đánh giá ngay lập tức)
x := 10
defer fmt.Println(x)
x = 99Tóm tắt lại
defer call()trì hoãn việc thực thi cho đến khi hàm trả về.- Nhiều lần trì hoãn = lệnh LIFO.
- Các đối số được đánh giá ngay lập tức, việc thực thi bị hoãn lại.
- Được sử dụng để dọn dẹp xác định: tập tin, mutexes, kết nối.
defer+recover()chặnpanic(hiếm, ở ranh giới).- Không bao giờ
deferbên trong một vòng lặp dài: nó sẽ tích lũy cho đến khi hàm bên ngoài trả về.