在本教程中,您将学习如何使用错误以及如何创建自己的自定义错误。Go 使用类似于 C 语言的错误处理方法,没有任何异常,但在其他语言(如 JAVA)中使用 try/catch 异常。Go 错误处理很简单,具有预定义的错误类型。
此外,我们还将在后面的教程中学习如何使用 panic 生成panic 错误和使用recover来克服它们。
错误是在正在执行的 Go 程序中发生的一个意外操作或事件。程序中的错误会影响正常的执行流程,并导致程序突然终止。错误也称为 bug。用于查找和解决编程语言中 bug 的方法称为调试。
Go 允许包和工具处理错误(即失误)。为了实现操作错误的功能,Go 提供了错误包。Go 对函数和方法中的微小错误返回一个错误对象。错误对象可能是唯一或最后一个返回值。如果函数没有问题,错误对象为 nil。如果我们收到调用语句中的任何错误,我们应该始终验证它们。
Go 编程语言不支持异常处理机制,与许多其他语言不同,Golang 不能抛出异常。相反,Golang 采用了新的错误处理机制,如 panic 和 recovery。
错误是一种类型。错误具有一个 Error() 方法,此方法以字符串形式返回错误消息的详细信息。错误是一种类型,其
// The built-in error interface is a regular interface for handling errors.
// where nil means no errors.
type error interface {
Error() string
}
如您所见,错误处理程序实际上是一个接口,其中包含一个简单的 Error() 方法,其返回值为字符串。
此定义告诉我们,要实现错误处理,所需做的就是向 Error() 方法返回一个简单的字符串。
func main() {
conent, err := openFile()
if err != nil {
fmt.Println(err)
} else {
fmt.Println(string(conent))
}
}
如果 err != nil(检测到错误存在),它将终止执行,否则将继续正常执行。
在 Go 中,许多函数返回多个值。通常,其中一个返回值是 error 类型。一个例子是 strconv.Atoi() 函数。此函数用于将字符串数据转换为数字。此函数返回 2 个返回值。第一个返回值是转换结果,第二个返回值是错误。当转换顺利时,第二个返回值将为 nil。同时,当转换失败时,可以立即从返回的错误中识别出原因。
下面是一个简单程序示例,用于检测用户输入是数字还是非数字。从中我们将学习错误的使用。
package main
import (
"fmt"
"strconv"
)
func main() {
var input string
fmt.Print("Type some number: ")
fmt.Scanln(&input)
var number int
var err error
number, err = strconv.Atoi(input)
if err == nil {
fmt.Println(number, "is number")
} else {
fmt.Println(input, "is not number")
fmt.Println(err.Error())
}
}
运行程序,它会显示“输入一些数字:”。输入一个自由数字,如果是,则按回车键。
输出
Type some number: is not number strconv.Atoi: parsing "": invalid syntax
fmt.Scanln(&input) 语句用于捕获用户在按下回车键之前输入的文本,然后将其作为字符串保存到 input 变量中。
然后使用 strconv.Atoi() 将变量转换为数字类型。该函数返回 2 个数据,由 number 和 err 接收。
第一个数据 (number) 包含转换结果。第二个数据 err 包含错误信息(如果在转换过程中发生错误)。
之后进行检查,如果没有错误,则显示数字。如果有错误,则显示输入以及错误消息。错误消息可以从错误类型的 Error() 方法中获取。
除了利用可用内部函数返回的错误之外,我们还可以使用 errors.New() 函数创建自己的错误对象(必须先导入 errors 包)。
以下示例展示了如何创建自定义错误。首先,准备一个名为 validate() 的函数,该函数将用于检查输入是否为空。如果为空,将生成一个新错误。
Package main
import (
"errors"
"fmt"
"strings"
)
func validate(input string) (bool, error) {
if strings.TrimSpace(input) == "" {
return false, errors.New("cannot be empty")
}
return true, nil
}
接下来在 main 函数中,创建一个简单的过程来捕获用户输入。利用 validate() 函数来检查输入。
在上面的程序中,函数 error.New() 定义了一个来自 error 包的新错误类型,并在括号内传递了相应的错误消息。
func main() {
var name string
fmt.Print("Type your name: ")
fmt.Scanln(&name)
if valid, err := validate(name); valid {
fmt.Println("hello", name)
} else {
fmt.Println(err.Error())
}
}
validate() 函数返回 2 条记录。第一个数据是一个布尔值,指示输入是否有效。第二个数据是错误消息(如果输入无效)。
strings.TrimSpace() 函数用于删除字符串前后空格字符。这是必需的,因为用户可以只输入一个空格然后回车。
当输入无效时,使用 errors.New() 函数创建一个新错误。此外,还可以通过 fmt.Errorf() 函数创建错误对象。
package main
import (
"errors"
"fmt"
"strings"
)
func validate(input string) (bool, error) {
if strings.TrimSpace(input) == "" {
return false, errors.New("cannot be empty")
}
return true, nil
}
func main() {
var name string
fmt.Print("Type your name: \n")
fmt.Scanln(&name)
if valid, err := validate(name); valid {
fmt.Println("hello", name)
} else {
fmt.Println(err.Error())
}
输出
Type your name: cannot be empty
在 Go 编程语言中,ioutil.ReadFile 读取文件并返回其内容。如果执行成功,调用会将 err 设置为 nil。
考虑一个带有 test.txt 文件的读取文件,其文本如下所示:

通过 Go 代码读取文件 test.txt 的程序如下
package main
import (
"fmt"
"io/ioutil"
"log"
)
var path = "C:/Users/Desktop/Golang/Tutorials/test.txt"
func main() {
content, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(content))
} }
}
if err != nil {
panic(err)
}
fmt.Println("==> file successfull")
fmt.Println(string(text))
}
输出
Windows PowerShell Copyright (C) 2014 Microsoft Corporation. All rights reserved. PS C:\Users\Desktop\Golang> go run errorread.go hello welcome to golang
通过设置错误的路径会发生错误,这会提供错误指示。为了识别差异,我们使用相同的程序,但将路径中的测试文件名更改为文本文件。
package main
import (
"fmt"
"io/ioutil"
"log"
)
var path = "C:/Users/Desktop/Golang/Tutorials/text.txt"
func main() {
content, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}
log.fatal 函数将错误打印到控制台,并通过调用 os.Exit 终止程序。
if err != nil {
log.Fatal(err)
}
输出
PS C:\Users\Desktop\Golang> go run errorread.go 2022/01/08 12:38:49 open C:/Users/Desktop/Golang/Tutorials/text.txt: The system cannot find the file specified. exit status 1
注意:要理解读取文件概念,请参阅文件教程
errors.Is 函数检查错误是否为指定类型。
让我们通过一个示例来理解它。
package main
import (
"errors"
"fmt"
"log"
"os"
)
var path = "C:/Users/Desktop/Golang/Tutorials/test.txt"
func main() {
if _, err := os.Open(path); err != nil {
if errors.Is(err, os.ErrNotExist) {
log.Fatal("file does not exist\t", err)
} else if errors.Is(err, os.ErrPermission) {
log.Fatal("insufficient permissions\t", err)
} else {
log.Fatal(err)
}
}
fmt.Println("...")
}
在上面的示例中,我们检查错误是否属于 os.ErrNotExist 或 os.ErrPermission 类型。
输出
Windows PowerShell Copyright (C) 2014 Microsoft Corporation. All rights reserved. PS C:\Users\Desktop\Golang> go run isfun.go ...
让我们通过一个程序来理解
package main
import (
"errors"
"fmt"
)
const Wr
var ErrInput = errors.New("bad input")
func validateInput(input string) error {
if input == WrongInput {
return fmt.Errorf("validateInput: %w", ErrInput)
}
return nil
}
func main() {
input := WrongInput
err := validateInput(input)
if errors.Is(err, ErrInput) {
fmt.Println("error due to wrong input")
}
}
在上述程序中,您可以观察到函数 validate input 为 WrongInput 返回一个错误。此错误是 ErrInput,它包装在由 fmt.Errorf() 创建的错误中。使用 Is(err, target error) bool 函数,即使错误被包装,我们也可以检测到 ErrInput,因为此函数会检查包装错误链中是否有任何错误与目标匹配。因此,这种形式应该优于 err == ErrInput 的比较。
输出
error due to wrong input Program exited.