面试题答案
一键面试1. 错误分类处理
- 使用自定义错误类型:在Go中,可以通过定义新的结构体类型并实现
error
接口来自定义错误类型。这样有助于区分不同类型的错误。type DatabaseError struct { ErrMsg string } func (de DatabaseError) Error() string { return de.ErrMsg } type NetworkError struct { ErrMsg string } func (ne NetworkError) Error() string { return ne.ErrMsg } func getData() (string, error) { // 模拟数据库错误 return "", DatabaseError{"Database connection failed"} } func main() { data, err := getData() if err != nil { if _, ok := err.(DatabaseError); ok { // 处理数据库错误 println("Handling database error:", err.Error()) } else if _, ok := err.(NetworkError); ok { // 处理网络错误 println("Handling network error:", err.Error()) } else { // 处理其他未知错误 println("Handling other error:", err.Error()) } } }
- 基于标准库错误类型分类:Go标准库中有一些预定义的错误类型,如
os.Error
等。对于涉及文件操作、系统调用等,可以根据标准库错误类型的特性进行分类处理。func readFile() error { _, err := os.Open("nonexistentfile.txt") return err } func main() { err := readFile() if err != nil { if os.IsNotExist(err) { // 文件不存在的处理 println("File does not exist, can create it.") } else if os.IsPermission(err) { // 权限错误处理 println("Permission denied.") } else { // 其他错误处理 println("Other file operation error:", err.Error()) } } }
2. 避免重复的错误处理代码
- 封装错误处理函数:将重复的错误处理逻辑封装成函数,这样在不同地方遇到相同类型的错误处理时可以直接调用。
func handleDatabaseError(err error) { if err != nil { if _, ok := err.(DatabaseError); ok { println("Database error occurred:", err.Error()) // 例如,尝试重新连接数据库 } } } func getDataFromDB() (string, error) { // 模拟数据库操作返回错误 return "", DatabaseError{"Database query failed"} } func main() { data, err := getDataFromDB() handleDatabaseError(err) }
- 使用
defer
和recover
(适用于特定场景):在一些需要确保资源正确释放并且处理可能的运行时错误的场景下,defer
和recover
可以结合使用来避免重复编写清理和错误处理代码。
这里func divide(a, b int) int { defer func() { if r := recover(); r != nil { println("Recovered from panic:", r) } }() return a / b } func main() { result := divide(10, 0) println("Result:", result) }
defer
函数捕获了可能因为除零操作产生的panic
,避免了在调用divide
函数的地方重复编写处理panic
的代码。但要注意,recover
应该只在defer
函数中使用,并且尽量避免滥用panic
,因为panic
会导致程序流程的突然改变。
通过这些方法,可以提高Go项目代码在处理错误时的可读性和可维护性。