自定义错误类型通过结构体实现error接口,可携带时间、位置等详细信息,如MyError记录时间和错误描述;错误包装使用%w动词将底层错误嵌入,保留原始上下文,便于通过errors.As解包获取根源错误;处理多返回值错误需及时检查并传递上下文;APIError示例包含错误码、消息和详情,提升调试效率;错误包装适用于保留上下文,错误链适合追踪传播路径,两者可结合使用;自定义错误用于需细分错误类型或附加信息的场景,标准错误适用于简单通用情况,如io.EOF表示文件结束。

Golang的
errors
自定义错误类型和包装现有错误,提供更丰富的错误信息和上下文。
自定义错误类型:结构体与接口的巧妙结合
Golang中并没有像其他语言那样的
try-catch
error
error
立即学习“go语言免费学习笔记(深入)”;
package main
import (
"fmt"
"time"
)
type MyError struct {
When time.Time
What string
}
func (e MyError) Error() string {
return fmt.Sprintf("%v: %v", e.When, e.What)
}
func run() error {
return MyError{
When: time.Now(),
What: "Something went wrong",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err)
}
}上面的代码定义了一个
MyError
Error()
error
错误包装:保留上下文,追溯根源
错误包装是指将一个错误包装到另一个错误中,这样可以保留原始错误的上下文信息。Golang 1.13引入了
errors.Wrap
fmt.Errorf
%w
package main
import (
"errors"
"fmt"
"os"
)
func readFile(filename string) ([]byte, error) {
f, err := os.Open(filename)
if err != nil {
return nil, fmt.Errorf("failed to open file: %w", err)
}
defer f.Close()
b := make([]byte, 100)
n, err := f.Read(b)
if err != nil {
return nil, fmt.Errorf("failed to read file: %w", err)
}
return b[:n], nil
}
func main() {
_, err := readFile("nonexistent_file.txt")
if err != nil {
fmt.Println(err)
// 解包错误,直到找到原始错误
var pathError *os.PathError
if errors.As(err, &pathError) {
fmt.Println("Failed at path:", pathError.Path)
}
}
}在这个例子中,
readFile
fmt.Errorf
%w
main
errors.As
os.PathError
如何优雅地处理多个返回值中的错误?
Golang函数经常返回多个值,其中一个通常是
error
package main
import (
"fmt"
"os"
)
func processFile(filename string) error {
f, err := os.Open(filename)
if err != nil {
return fmt.Errorf("failed to open %s: %w", filename, err)
}
defer f.Close()
// ... 更多操作
return nil
}
func main() {
err := processFile("my_file.txt")
if err != nil {
fmt.Println(err)
}
}这里的关键在于,每次调用可能返回错误的函数时,都要立即检查错误,并进行处理或返回。 错误信息应包含足够的上下文,方便定位问题。
自定义错误类型应该包含哪些信息?
自定义错误类型的设计取决于具体的应用场景,但通常应该包含以下信息:
package main
import (
"fmt"
"time"
)
type APIError struct {
Time time.Time
Code int
Message string
Details map[string]interface{}
}
func (e APIError) Error() string {
return fmt.Sprintf("[%d] %s: %v", e.Code, e.Message, e.Details)
}
func callAPI() error {
return APIError{
Time: time.Now(),
Code: 500,
Message: "Internal Server Error",
Details: map[string]interface{}{
"endpoint": "/users",
"method": "GET",
},
}
}
func main() {
err := callAPI()
if err != nil {
fmt.Println(err)
}
}这个例子中的
APIError
错误包装与错误链:如何选择合适的策略?
错误包装和错误链是两种不同的错误处理策略。错误包装是将一个错误包装到另一个错误中,保留原始错误的上下文信息。错误链则是将多个错误连接起来,形成一个链式结构,记录错误的传递路径。
选择哪种策略取决于具体的应用场景。如果需要保留原始错误的上下文信息,可以选择错误包装。如果需要记录错误的传递路径,可以选择错误链。 在实际应用中,也可以将这两种策略结合起来使用。
什么时候应该使用自定义错误类型,什么时候应该使用标准错误?
使用自定义错误类型的情况:
使用标准错误的情况:
一般来说,对于应用程序内部的错误,可以使用自定义错误类型。对于与外部系统交互时发生的错误,可以使用标准错误。 例如,
io.EOF
以上就是Golang errors库自定义错误与包装技巧的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号