面试题答案
一键面试- 合并defer操作:
- 如果有多个defer语句是针对类似的资源清理或日志记录等操作,可以将它们合并为一个defer语句。例如,如果有多个文件关闭的defer语句,可以将文件句柄存储在一个切片中,然后在一个defer语句中统一关闭。
var files []*os.File // 打开文件并添加到切片 file1, err := os.Open("file1.txt") if err != nil { // 错误处理 } files = append(files, file1) file2, err := os.Open("file2.txt") if err != nil { // 错误处理 } files = append(files, file2) defer func() { for _, file := range files { file.Close() } }()
- 避免在defer中执行复杂操作:
- defer语句中的函数应该尽量简单,避免在其中执行耗时的I/O操作、复杂的计算等。例如,如果需要记录日志,在defer中简单地调用一个记录日志的函数,而不是在该函数内部进行复杂的日志格式化和网络传输等操作。可以提前准备好日志信息,在defer中快速记录。
logInfo := fmt.Sprintf("Operation completed with result: %v", result) defer func() { log.Println(logInfo) }()
- 条件执行defer:
- 如果某些defer操作只有在特定条件下才需要执行,可以在函数中使用条件判断,只有满足条件时才定义defer语句。例如,只有在成功打开数据库连接时才定义关闭连接的defer语句。
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database") if err != nil { // 错误处理 return } defer db.Close()
- 减少defer的嵌套:
- 深度嵌套的defer语句可能会增加栈的开销和理解成本。尽量将defer语句放在函数的外层,保持代码结构清晰,减少不必要的嵌套。例如,在一个多层嵌套的循环或条件语句中,将defer语句移到最外层函数体中,只要确保资源在函数结束时能正确清理即可。
func outerFunction() { // 资源获取 resource, err := acquireResource() if err != nil { // 错误处理 return } defer releaseResource(resource) for i := 0; i < 10; i++ { // 内层逻辑 for j := 0; j < 5; j++ { // 更内层逻辑 } } }