Go 语言入门指南:基础语法和常用特性解析
学到高质量编程内容,记录一下其中的错误处理部分。
error接口类型
在Go语言中,错误处理是使用error接口来完成的。error是一个内置的接口类型,定义在Go的标准库中
type error interface {
Error() string
}
这个接口非常简单,只有一个Error()方法,该方法返回一个描述错误的字符串。在go当中任何实现了该接口的类型都被称之为错误类型,也可以直接定义一个MyError结构体并实现该方法
1.错误处理
在Go中,错误通常作为函数的最后一个返回值返回。调用者应该检查这个返回值来确定是否发生了错误
value, err := someFunction()
if err != nil {
// 错误处理逻辑
log.Println("发生错误:", err)
return
}
// 使用value继续处理
2.错误链(Chaining)
错误链是错误包装的一个变体,它允许你创建一个错误链,每个错误都包含前一个错误的上下文
err := doSomething()
if err != nil {
return fmt.Errorf("在doSomething中发生错误: %w", err)
}
3. 错误处理最佳实践
- 不要忽略错误,即使你认为它不可能发生。
- 尽可能地提供详细的错误信息。
- 考虑错误应该被处理还是向上传递。
- 使用错误包装来添加上下文信息,而不是覆盖原始错误。
errors.New()方法
简单错误指的是仅出现一次的错误,而且在其他地方不需要捕捉。当你需要在代码中表示一个简单错误时,可以使用 errors.New 来创建一个新的错误对象。这个对象可以被返回给调用者,或者用于其他错误处理逻辑。
func New(text string) error // 返回值是实现了error接口的对象
result,err := divide(10,0)
fmt.Println("Error:",err) // fmt包对error类型进行了特殊处理,可以直接打印
你有一个实现了 error 接口的对象时,你可以像处理其他错误一样处理它,比如打印错误消息、根据错误类型做出决策等。由于 error 接口只要求有一个 Error 方法,因此你可以根据需要为错误类型添加额外的字段和方法,以满足你的特定需求。
错误的Wrap和Unwrap
错误的wrap是指提供了一个error嵌套到另一个error上的能力 可以利用fmt.Errorf中使用%w关键字来将一个错误关联到另一个错误中
return fmt.Errorf("reading srcfiles list: %w",err) // 返回的是一个错误对象
errors.As()方法
errors.As 函数用于判断一个错误是否为特定的类型。如果错误确实是该类型,则 errors.As 会将其转换为该类型的值(通过指针参数)。这对于处理具有特定字段或方法的自定义错误类型非常有用。
if errors.As(err, &myErr) { // 断言成功则将err的值存入myErr中
fmt.Println("The error is of type *MyError:", myErr.Msg)
} else {
fmt.Println("The error is not of type *MyError.")
}
panic()函数
- 当程序出现不可逆转的错误时,可以使用panic
- 调用单数不包含panic会造成程序的崩溃
panic的作用
- 中断执行:当panic被调用时,它会立即中断当前函数的执行,并停止正常的控制流。
- 执行defer语句:在panic触发后,Go运行时系统会立即执行当前goroutine中所有已注册的defer语句。这些defer语句通常用于进行必要的清理操作,如关闭文件、释放资源等。
- 打印堆栈信息:panic会打印出调用堆栈信息,这有助于开发者定位问题发生的位置和原因。堆栈信息详细记录了程序崩溃时的状态和panic触发的调用路径。
- 程序崩溃:如果没有通过recover函数捕获panic,程序将崩溃并终止运行
recover()函数
主要用于从panic状态中恢复程序的执行
- recover只能在当前的goruoutine当中生效
- defer语句的执行是后进先出的
- 恢复执行:
recover()可以在defer修饰的函数中捕获由panic触发的异常,并允许程序从异常点恢复执行,而不是直接崩溃退出。 - 返回值:如果
recover()在defer函数中被调用,且当前有panic正在发生,recover()会返回传递给panic的值。如果没有panic发生,recover()会返回nil。
学习总结
目前感觉Go中存在许多C++语言中不存在的特性,如切片、错误类型、接口类,代码写起来有不小的区别,不过语法简洁好上手,学起来比C/C++有意思许多。