Golang中的错误处理的示例详解
作者:梦想画家
本文介绍Golang错误处理机制,包括不同类型错误处理、定义运行时错误等内容。
golang错误处理机制
Go错误处理类似C语言,没有提供任何异常,以及类java语言使用的try/catch异常处理机制。go异常处理仅简化为预定义的Error类型,Go没有提供异常处理机制,不能抛出类似许多其他语言的异常。相反,Golang集成了新的错误处理机制,如panic 和 recovery。
error类型
error类型仅包括Error方法,返回string类型标识具体的错误信息。代码如下:
// 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中很多函数返回多个值,通常其中一个返回值是错误类型。举例: strconv.Atoi()
,转换字符串数据为数值类型,返回两个值,第一个是转换结果,第二个是错误。如果正常转换,第二个返回值为nil。反之转换失败,可从错误中获得错误原因。
下面示例检查用户输入数据是否为数值,通过示例可以学习如何处理错误:
package main import ( "fmt" "strconv" ) func main() { var input string fmt.Print("Type some number: ") fmt.Scanln(&input) number, err := strconv.Atoi(input) if err == nil { fmt.Println(number, "is number") } else { fmt.Println(input, "is not number") fmt.Println(err.Error()) } }
如果有错误显示错误信息,反之输出结果。
创建错误对象
内置方法
除了内置函数返回错误,我们可以创建错误,主要有两种方法:
- errors.New()
- fmt.Errorf()
下面示例展示如何自定义错误对象。首先提供一个validate()对象,之后用于检查用户数是否为空,如果为空产生错误:
func validate(input string) (bool, error) { if strings.TrimSpace(input) == "" { return false, fmt.Errorf("%s can't be empty", 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()) } }
第三方库
有时需要在错误对象上增加额外信息:
import "github.com/pkg/errors" internal := errors.New("internal error") // 给error增加其他上下文信息 wrapped := errors.Wrap(internal, "wrapper") // 获得原始错误信息 unwrapped := errors.Cause(wrapped)
pkg/errors是内置errors的替代工具,尽管内置error也提供了类似功能:
import "errors" internal := errors.New("internal error") // add additional context to an error wrapped := fmt.Errorf("wrapper: %w", internal) // get original error unwrapped := errors.Unwrap(wrapped)
但内置功能相对较少,建议直接使用pkg/errors.
完整示例:
import ( "fmt" "github.com/pkg/errors" "strings" ) func validate(input string) (bool, error) { if strings.TrimSpace(input) == "" { err := errors.New("can't be empty") return false, errors.Wrap(err, "input error") } 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(errors.Unwrap(err)) } }
panic
panic是Go内置函数,类似其他语言的异常。当运行时出现该函数,则程序在该点终止。
声明panic
go代码中遇到panic时,不再继续执行。这种这种场景可以使用内置panic函数:
func panic( interface{} )
可以传入字符串或其他类型参数,情况示例:
package main import "fmt" func main() { fmt.Println("start Go program") panic(" built in panic keyword gives error msg") // panic keyword fmt.Println("End Go program") }
内置操作
package main import ( "fmt" ) func main() { a,b := 1,0 // variable a & b are declared and initialized result := a/b // division operation fmt.Println(result) }
上面代码因为除数为0,程序终止并报错:panic: runtime error: integer divide by zero
另外方法slice时,索引超出范围时也会panic:
package main import "fmt" func main() { names := []string{ //slice data type "Learn eTutorials", // index 0 "Golang", //index 1 "panic tutorial", //index 2 } //fmt.Println(names[0]) commented //fmt.Println(names[2]) commented fmt.Println(names[4]) //panic: runtime error: index out of range [4] with length 3 }
那么时间使用panic函数呢?
- 当程序不能继续执行时使用。举例,web服务器不能绑定特定端口。
- 程序出错时使用。举例,假设方法接收指针类型参数,实际调用时传入nil。
panic与defer
还是从示例开始吧:
func Name(firstName *string, lastName *string) { defer fmt.Println("Name function deferred call") if firstName == nil { panic("runtime error: first name cannot be nil") } if lastName == nil { panic("runtime error: last name cannot be nil") } fmt.Printf("%s %s\n", *firstName, *lastName) fmt.Println("return from Name") } func main() { defer fmt.Println("main() deffered call") firstName := "Elon" Name(&firstName, nil) fmt.Println("return from main") }
输出结果为:
Name function deferred call
main() deffered call
panic: runtime error: last name cannot be nil
我们看到多个defer,类似栈,先进后出。panic总是让所有defer执行完毕后才抛出。
recover
前面我们看了error和panic两类异常,前者类似java中的运行时异常,后者类似于非运行时异常。error我们可以捕获或忽略,但panic要么终止运行,要么手动恢复,也就是手动处理这类错误,如给用户提示。下面同时示例来说明:
func main() { fmt.Println("lets learn about recover() in golang") Panicfunc() fmt.Println("learned all about recover() ") } func Panicfunc() { defer Panicrecover() fmt.Println("instruction just before panicking situation") panic("Panicfunc resume execution") fmt.Println("instruction after panic does not execute") } func Panicrecover() { if err := recover(); err != nil { fmt.Printf("Recovered from panic: %v \n", err) } }
输出结果:
lets learn about recover() in golang
instruction just before panicking situation
Recovered from panic: Panicfunc resume execution
learned all about recover()
我们看到panic之后代码不会执行,但recover捕获的错误处理代码能够执行。
到此这篇关于Golang中的错误处理的示例详解的文章就介绍到这了,更多相关Go错误处理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!