面试题答案
一键面试1. 设计自定义 panic 类型
在 Go 语言中,可以通过定义结构体类型来创建自定义 panic 类型。例如,假设我们有一个处理用户认证的业务场景,当认证失败时触发自定义 panic。
package main
import "fmt"
// AuthFailedError 自定义认证失败 panic 类型
type AuthFailedError struct {
Reason string
}
func (e *AuthFailedError) Error() string {
return fmt.Sprintf("认证失败: %s", e.Reason)
}
2. 实现触发自定义 panic
func authenticateUser(username, password string) {
if username != "admin" || password != "secret" {
panic(&AuthFailedError{Reason: "用户名或密码错误"})
}
fmt.Println("认证成功")
}
3. 恢复策略设计
使用 recover
函数来捕获并处理自定义 panic。在捕获到 panic 后,根据业务需求进行相应处理,例如记录日志、返回特定错误信息给用户等。
func main() {
defer func() {
if r := recover(); r != nil {
if err, ok := r.(*AuthFailedError); ok {
fmt.Printf("捕获到认证失败 panic: %v\n", err)
// 这里可以进行业务相关的恢复操作,比如提示用户重新输入
} else {
panic(r) // 不是我们定义的 panic 类型,重新抛出
}
}
}()
authenticateUser("test", "wrongpass")
}
4. 多线程环境下的可行性及潜在问题
- 可行性:
- Go 语言的
defer
和recover
机制在 goroutine (Go 语言的轻量级线程)中同样有效。每个 goroutine 都有自己独立的栈,因此在一个 goroutine 中发生的 panic 不会影响其他 goroutine,只要在每个 goroutine 中正确设置defer
来捕获 panic,就可以实现安全的错误处理。
- Go 语言的
- 潜在问题:
- 资源泄漏:如果在 panic 发生前有未关闭的资源(如文件句柄、数据库连接等),可能导致资源泄漏。需要确保在 panic 前正确关闭资源,或者在
recover
后进行资源清理。 - 共享状态:如果多个 goroutine 共享某些状态,在一个 goroutine 中发生 panic 可能导致共享状态处于不一致的状态。在恢复时需要仔细处理共享状态,确保一致性。
- 死锁风险:在
recover
过程中,如果操作不当,可能引入死锁。例如在持有锁的情况下发生 panic,恢复时又尝试获取同一个锁。需要注意锁的使用和释放策略。
- 资源泄漏:如果在 panic 发生前有未关闭的资源(如文件句柄、数据库连接等),可能导致资源泄漏。需要确保在 panic 前正确关闭资源,或者在