
在 Go 语言中,panic 是一种用于报告程序运行时错误的机制。recover 函数则允许程序从 panic 状态中恢复,避免程序崩溃。然而,recover 的使用存在一些限制,理解这些限制对于编写健壮的 Go 程序至关重要。
recover 只能在 deferred 函数中生效
如上所述,recover 函数只能在 deferred 函数中被调用才能生效。这是 Go 语言设计上的一个特性。当程序发生 panic 时,Go 运行时系统会沿着调用栈向上寻找 deferred 函数,并依次执行这些函数。如果在某个 deferred 函数中调用了 recover,则 panic 会被捕获,程序可以从 panic 状态恢复,并继续执行 recover 函数之后的代码。
考虑以下示例:
package main
import "fmt"
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
fmt.Println("Starting...")
panic("Something went wrong!")
fmt.Println("Ending...") // 这行代码不会被执行
}在这个例子中,panic("Something went wrong!") 会触发一个 panic。由于我们在 main 函数中定义了一个 deferred 函数,并在该函数中调用了 recover,因此 panic 被捕获,程序会打印 "Recovered from panic: Something went wrong!",然后继续执行 deferred 函数之后的代码。如果没有 deferred 函数和 recover,程序将会崩溃。
注意事项:
- recover 只能在 deferred 函数中直接调用,如果在其他函数中调用 recover,则 recover 不会生效。
- 如果没有 panic 发生,recover 会返回 nil。
deferred 函数在死锁情况下不被调用
当程序发生死锁时,Go 运行时系统不会调用 deferred 函数。这是 Go 语言设计者的一个有意选择。他们的假设是,从死锁中恢复在实践中几乎是不可能的。
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
死锁通常是由于多个 goroutine 互相等待对方释放资源而造成的。在这种情况下,程序无法继续执行,因此调用 deferred 函数也无法解决死锁问题。
考虑以下示例:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu1, mu2 sync.Mutex
defer func() {
fmt.Println("Deferred function called") // 不会被执行
}()
mu1.Lock()
mu2.Lock()
go func() {
mu2.Lock()
time.Sleep(time.Second)
mu1.Lock()
fmt.Println("Goroutine 1")
mu1.Unlock()
mu2.Unlock()
}()
go func() {
mu1.Lock()
time.Sleep(time.Second)
mu2.Lock()
fmt.Println("Goroutine 2")
mu2.Unlock()
mu1.Unlock()
}()
time.Sleep(2 * time.Second) // 等待一段时间,让死锁发生
fmt.Println("Main function")
}在这个例子中,两个 goroutine 互相等待对方释放锁,导致死锁。由于发生了死锁,deferred 函数不会被调用,因此 "Deferred function called" 不会被打印。
总结:
- recover 只能在 deferred 函数中生效,用于从 panic 状态中恢复。
- deferred 函数在死锁情况下不会被调用。
理解这些概念对于编写健壮的 Go 程序至关重要。在处理可能发生 panic 的代码时,应该使用 deferred 函数和 recover 来捕获 panic,避免程序崩溃。同时,应该注意避免死锁的发生,因为死锁会导致程序无法继续执行。









