Defer


📘 1. defer là gì?

defer trong Go dùng để trì hoãn thực thi một hàm cho đến khi hàm hiện tại kết thúc (return, panic, hoặc exit).

Nói cách khác:

defer giống như “cleanup hook” — nó sẽ chạy cuối cùng, bất kể bạn thoát hàm kiểu gì.


🔧 2. Cách dùng cơ bản

func main() {
    defer fmt.Println("Defer run at the end")
    fmt.Println("Main function start")
}

🧾 Output:

Main function start
Defer run at the end

⛓️ 3. Thứ tự thực thi (LIFO)

Các defer được stack lại và chạy theo thứ tự Last In First Out (LIFO).

func main() {
    defer fmt.Println("first")
    defer fmt.Println("second")
    defer fmt.Println("third")
}

🧾 Output:

third
second
first

📌 4. Use cases thường gặp

✅ a. Đóng tài nguyên

file, err := os.Open("data.txt")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

Không cần nhớ phải close cuối hàm — cực kỳ sạch & an toàn.


✅ b. Lock / Unlock

mu.Lock()
defer mu.Unlock()

Tránh quên Unlock() — giúp goroutine không bị deadlock.


✅ c. Transaction / Rollback

tx := db.Begin()
defer func() {
    if r := recover(); r != nil {
        tx.Rollback()
        panic(r)
    } else {
        tx.Commit()
    }
}()

Kết hợp với recover để rollback nếu panic.


✅ d. Timing / Logging

start := time.Now()
defer func() {
    log.Printf("done in %s", time.Since(start))
}()

⚠️ 5. Lưu ý quan trọng

⚠️ a. Tham số được đánh giá ngay lập tức

func main() {
    x := 10
    defer fmt.Println(x) // ✅ in ra 10
    x = 20
}

Biến x được chụp ngay lúc defer được gọi.


⚠️ b. defer ảnh hưởng đến hiệu năng nếu lặp quá nhiều

Dù rất tiện lợi, nhưng defer tạo một stack nên:

for i := 0; i < 1_000_000; i++ {
    defer func() {}() // ❌ tốn nhiều RAM & chậm
}

Tránh defer trong tight loop nếu performance quan trọng.


✅ Ưu điểm của defer

Ưu điểm
Giải thích

Rõ ràng, sạch code

Đảm bảo cleanup được gọi ở đúng chỗ

Giảm lỗi logic

Tránh quên đóng tài nguyên

Hữu ích khi panic

Vẫn chạy dù bị panic


❌ Nhược điểm của defer

Nhược điểm
Giải thích

Hiệu năng thấp hơn gọi trực tiếp

Vì lưu lại stack defer

Dễ hiểu nhầm thứ tự

Khi dùng nhiều defer lồng nhau

Không reset được thứ tự

Không thể thay đổi LIFO order


🧠 Best Practices (theo Senior Dev)

Tình huống
Cách dùng

Mở file, DB, net.Conn

defer Close() ngay sau khi mở

Lock

defer Unlock() ngay sau Lock()

Nhiều cleanup liên tục

Tách hàm, không nhồi nhiều defer

Panic recovery

Kết hợp defer + recover để rollback, log


Last updated