> For the complete documentation index, see [llms.txt](https://denglj.gitbook.io/essential-go/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://denglj.gitbook.io/essential-go/18-error-handling.md).

# 18 错误处理

错误处理基本用法：

```go
package main

import (
	"fmt"
	"math"
)

func sqrt(n float64) (float64, error) {
	if n < 0 {
		return 0, fmt.Errorf("invalid argument '%f', must be >= 0", n)
	}
	return math.Sqrt(n), nil
}

func printSqrt(n float64) {
	if res, err := sqrt(n); err == nil {
		fmt.Printf("sqrt of %f is %f\n", n, res)
	} else {
		fmt.Printf("sqrt of %f returned error '%s'\n", n, err)
	}

}

func main() {
	printSqrt(16)
	printSqrt(-16)
}

// 输出结果
// sqrt of 16.000000 is 4.000000
// sqrt of -16.000000 returned error 'invalid argument '-16.000000', must be >= 0'
```

跟C#和Python不同，Go的错误处理是直接返回错误值，而不是抛出异常。

Go也提供了[恐慌和恢复](/essential-go/20-panic-and-recover.md)的异常机制，但它们应该被尽量少用。

错误也是值，就像整数或字符串一样。

`error`类型是一个内置(built-in)接口类型，该接口规定了`Error() string`方法。

如果要表示执行成功，则把表示错误的变量置为`nil`返回。

若要表示执行失败，则把错误变量赋值为`errors.New(msg string)`或`fmt.Errorf(format string, args... interface{})`返回的值。

您也可以通过自定义一个结构体并实现`Error() string`方法来[自定义错误类型](/essential-go/18-error-handling/custom-error-types.md)。

如果一个函数要返回错误，那么错误值应当总是最后一个。

应始终检查函数的返回值中是否包含错误。编写鲁棒性强的软件的关键就是检查错误并进行适当处理。初学者通常放弃检查错误，然后面临调试神秘故障的麻烦。

## 译者注：`error`源码解读

```go
// error接口的定义
// src/builtin/builtin.go
type error interface {
	Error() string
}

// error的实现
// src/errors/errors.go

// New returns an error that formats as the given text.
// Each call to New returns a distinct error value even if the text is identical.
func New(text string) error {
	return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}
```

就这么多，没了。是不是简单到爆。`error`仅仅是一种普通的`interface`类型，包含一个返回类型为字符串的`Error()`函数。
