error接口
# Go 的 error
接口介绍
在 Go 语言中,error
是一个内置的接口,用于表示和处理错误。error
接口的定义非常简单:
type error interface {
Error() string
}
1
2
3
2
3
只要一个类型实现了 Error()
方法,并返回一个字符串,就可以被视为实现了 error
接口。这种设计使得错误处理在 Go 中变得简洁和灵活。
# 1. Go 的 error
接口基本用法
# 1.1 创建和返回错误
标准库提供了一个内置的函数 errors.New
,用于创建一个简单的错误:
package main
import (
"errors"
"fmt"
)
func main() {
err := errors.New("this is an error")
fmt.Println(err)
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
输出:
this is an error
1
# 1.2 使用 fmt.Errorf
创建格式化错误
fmt.Errorf
可以创建带有格式化信息的错误:
package main
import (
"fmt"
)
func main() {
err := fmt.Errorf("file %s not found", "example.txt")
fmt.Println(err)
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
输出:
file example.txt not found
1
# 2. 自定义错误类型
在实际开发中,我们通常需要自定义错误类型,以提供更多的错误上下文信息。
# 2.1 定义自定义错误类型
package main
import (
"fmt"
)
type MyError struct {
Code int
Message string
}
func (e MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
func main() {
err := MyError{Code: 404, Message: "Resource not found"}
fmt.Println(err)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
输出:
Error 404: Resource not found
1
# 3. 错误处理的基本模式
Go 的错误处理主要依赖返回值,并通过检查错误值是否为 nil
来判断是否发生了错误。
package main
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", result)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
输出:
Error: division by zero
1
# 4. 错误处理的最佳实践
# 4.1 包装错误
Go 提供了 errors.Unwrap
、errors.Is
和 errors.As
等工具,用于解包和判断错误类型。
package main
import (
"errors"
"fmt"
)
func main() {
baseErr := errors.New("base error")
wrappedErr := fmt.Errorf("wrapped: %w", baseErr)
fmt.Println(wrappedErr) // 输出: wrapped: base error
// 检查是否是特定错误
if errors.Is(wrappedErr, baseErr) {
fmt.Println("wrappedErr contains baseErr")
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
输出:
wrapped: base error
wrappedErr contains baseErr
1
2
2
# 4.2 类型断言和错误上下文处理
通过类型断言处理自定义错误类型:
package main
import (
"fmt"
)
type MyError struct {
Code int
Message string
}
func (e MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
func doSomething() error {
return MyError{Code: 403, Message: "Forbidden"}
}
func main() {
err := doSomething()
if err != nil {
// 检查是否是 MyError 类型
if e, ok := err.(MyError); ok {
fmt.Printf("Custom Error - Code: %d, Message: %s\n", e.Code, e.Message)
} else {
fmt.Println("Other Error:", err)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
输出:
Custom Error - Code: 403, Message: Forbidden
1
# 5. 实际应用案例
# 5.1 文件读取错误处理
package main
import (
"fmt"
"os"
)
func readFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("failed to open file %s: %w", filename, err)
}
defer file.Close()
fmt.Println("File opened successfully")
return nil
}
func main() {
err := readFile("nonexistent.txt")
if err != nil {
fmt.Println("Error:", err)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
输出:
Error: failed to open file nonexistent.txt: open nonexistent.txt: no such file or directory
1
# 5.2 数据库操作错误处理
package main
import (
"database/sql"
"errors"
"fmt"
_ "github.com/mattn/go-sqlite3" // SQLite driver
)
func getUserByID(db *sql.DB, id int) (string, error) {
var username string
err := db.QueryRow("SELECT username FROM users WHERE id = ?", id).Scan(&username)
if errors.Is(err, sql.ErrNoRows) {
return "", fmt.Errorf("user with id %d not found: %w", id, err)
}
if err != nil {
return "", fmt.Errorf("database error: %w", err)
}
return username, nil
}
func main() {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
fmt.Println("Error connecting to database:", err)
return
}
defer db.Close()
// Create a dummy table
db.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT)")
username, err := getUserByID(db, 1)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Username:", username)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
输出:
Error: user with id 1 not found: sql: no rows in result set
1
# 6. 总结
error
是 Go 内置的接口,通过Error()
方法返回错误信息。- 使用
errors.New
和fmt.Errorf
快速创建错误;也可以通过自定义类型实现复杂错误。 - Go 提供了错误包装工具(
%w
)、解包(errors.Unwrap
)、判断(errors.Is
和errors.As
)来处理复杂错误场景。 - 错误处理贯穿 Go 编程的各个层面,是保证程序健壮性的关键。
上次更新: 2024/11/21, 10:50:23