面试题答案
一键面试错误处理策略
- 常规错误处理:在Go语言中,对于可预期的错误,使用常规的错误返回机制。例如:
func readFileContent(filePath string) (string, error) {
data, err := ioutil.ReadFile(filePath)
if err != nil {
return "", err
}
return string(data), nil
}
- 不可预期错误(panic):对于不可预期的严重错误,如程序逻辑错误、内存不足等,使用
panic
。例如:
func divide(a, b int) int {
if b == 0 {
panic("division by zero")
}
return a / b
}
异常传播机制
- 函数调用链中的传播:当一个函数
panic
时,它会立即停止执行,并开始展开调用栈。例如:
func funcC() {
panic("error in funcC")
}
func funcB() {
funcC()
}
func funcA() {
funcB()
}
在上述代码中,funcC
的panic
会导致funcB
和funcA
的调用栈展开。
2. 跨Go协程传播:在Go协程中,panic
默认不会影响其他协程。但可以通过通道来传递panic
信息,例如:
func worker(errChan chan error) {
defer func() {
if r := recover(); r != nil {
errChan <- fmt.Errorf("recovered panic: %v", r)
}
}()
// 可能发生panic的代码
}
资源清理
- defer语句:使用
defer
语句进行资源清理,确保在函数结束时,无论是正常返回还是panic
,资源都能正确释放。例如:
func writeToFile(filePath string, content string) error {
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(content)
return err
}
- 自定义清理函数:对于复杂资源,可以定义专门的清理函数,并在
defer
中调用。例如:
type Connection struct {
// 连接相关的字段
}
func (c *Connection) Close() {
// 关闭连接的逻辑
}
func useConnection() {
conn := &Connection{}
defer conn.Close()
// 使用连接的逻辑
}
结合recover机制保证系统稳定性
- 顶层recover:在主函数或关键的入口函数中,使用
recover
来捕获panic
,防止程序崩溃。例如:
func main() {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from panic: %v", r)
// 可以进行一些恢复操作,如重启相关服务
}
}()
// 启动分布式系统的逻辑
}
- Go协程内的recover:在每个Go协程中,使用
defer
和recover
来捕获可能的panic
,确保单个协程的崩溃不会影响整个系统。例如:
func worker() {
defer func() {
if r := recover(); r != nil {
log.Printf("Worker recovered from panic: %v", r)
}
}()
// 协程具体逻辑
}
设计思路总结
- 分层处理:在不同的层次(函数、协程、系统入口)分别设计错误处理和异常捕获机制,确保异常在不同层面都能得到适当处理。
- 日志记录:在捕获
panic
或处理错误时,记录详细的日志信息,方便定位问题。 - 恢复策略:根据系统的实际需求,制定合理的恢复策略,如自动重启失败的服务、重新连接丢失的资源等,以保证系统的高可靠性和容错性。