Go – Panic và recover

Panic tương tự như là việc đưa ra một Exception. Nói cách khác, một Panic là một Exception trong Go. Một Panic được gây ra bởi một lỗi trong lúc chạy hoặc gọi thẳng đến hàm Panic được tích hợp sẵn trong Go.

Cách phổ biến xử lý khi gặp điều kiện bất thường trong Go là sử dụng errors. errors là đủ cho hầu hết các trường hợp bất thường phát sinh trong chương trình.

Nhưng trong một vài trường hợp chương trình không thể tiếp tục chạy bình thường khi gặp tình huống bất thường. Trong trường hợp này chúng ta sử dụng Panic để chấm dứt chương trình. Khi một hàm gặp Panic, nó lập tức dừng xử lý, hàm bất kỳ được defer sẽ được chạy và sau đó kiểm soát trả về cho phía gọi. Tiến trình này tiếp tục cho tới khi tất cả các hàm của goroutine hiện tại hoàn toàn được trả về, tại thời điểm đó chương trình in ra thông báo Panic, cùng với thông tin stack lỗi và sau đó kết thúc.

Khi một Panic được gọi xử lý thông thường của goroutine sẽ tạm dừng ngay lập tức:

  1. Khi một chương trình bị panic, nó sẽ ngay lập tức giải phóng stack gọi
  2. Điều này sẽ tiếp tục cho tới khi chương trình lỗi và in ra thông tin stack lỗi, hoặc cho tới khi hàm tích hợp recover được gọi.

Panic

Panic được định nghĩa như sau

func panic(interface{})

Các tham số được truyền cho Panic sẽ được in ra khi chương trình chấm dứt.

Để hiểu rõ hơn hãy cùng xem ví dụ sau

package main

import (  
    "fmt"
)

func fullName(firstName *string, lastName *string) {  
    if firstName == nil {
        panic("runtime error: first name cannot be nil")
    }
    if lastName == nil {
        panic("runtime error: last name cannot be nil")
    }
    fmt.Printf("%s %s\n", *firstName, *lastName)
    fmt.Println("returned normally from fullName")
}

func main() {  
    firstName := "Elon"
    fullName(&firstName, nil)
    fmt.Println("returned normally from main")
}

Bên trên là chương trình đơn giản dùng để in ra tên đầy đủ của một người. Hàm fullname sẽ in ra tên đầy đủ của một người. Hàm này kiểm tra xem liệu con trỏ firstNamelastNamenil hay không. Nếu nil thì hàm sẽ gọi panic với thông báo lỗi tương ứng. Thông báo lỗi này sẽ được in ra khi chương trình kết thúc.

Truyền vào Elon cho firstName, còn nil cho lastName. Do giá trị được truyền vào thoả mãn điều kiện nil nên chương trình panic. Khi panic xảy ra, chương trình chấm dứt, in ra tham số được truyền cho panic, theo kèm với thông tin stack lỗi.

Kết quả

panic: runtime error: last name cannot be nil

goroutine 1 [running]:  
main.fullName(0x1040c128, 0x0)  
    /tmp/sandbox135038844/main.go:12 +0x120
main.main()  
    /tmp/sandbox135038844/main.go:20 +0x80

Recover từ panic

Recover là hàm được tích hợp sẵn trong Go, được sử dụng để lấy lại kiểm soát của goroutine đang panic.

Hàm recover được định nghĩa như sau

recover() interface{}

Hàm recover trả về giá trị được truyền cho hàm panic và không bị Side Effect. Nghĩa là nếu goroutine không bị panic, hàm recover sẽ trả về nil. Do đó việc kiểm tra giá trị trả về của recovernil là cách tốt để biết được rằng chương trình bị panic hay không. Hãy cùng xem ví dụ sau

package main

import "fmt"

func defFoo() {
	fmt.Println("defFoo() started")

	if r := recover(); r != nil {
		fmt.Println("WOHA! Program is panicking with value", r)
	}

	fmt.Println("defFoo() done")
}

func normMain() {

	fmt.Println("normMain() started")

	defer defFoo() // defer defFoo call

	panic("HELP") // panic here

	fmt.Println("normMain() done")
}

func main() {
	fmt.Println("main() started")

	normMain() // normal call

	fmt.Println("main() done")
}

Hàm normMain gọi bên trong hàm main() mà thực hiện defer khi gọi hàm defFoo(). Sau đó chương trình bị panic nên không có câu lệnh nào sau đấy được thực hiện, sau đó chương trình gọi hàm defer defFoo(), trong hàm này chúng ta có xử lý recover() để kiểm tra chương trình panic hay không. Do chương trình bị panic nên chúng ta in ra thông tin stack lỗi của Panic.

Kết quả

main() started
normMain() started
defFoo() started
WOHA! Program is panicking with value HELP
defFoo() done
main() done

 

 

You May Also Like

About the Author: Nguyen Dinh Thuc

Leave a Reply

Your email address will not be published.