Golang 错误处理机制详解
创始人
2024-02-27 10:27:57
0

本文介绍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 stringfmt.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 stringfmt.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 stringfmt.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 keywordfmt.Println("End Go program")}

内置操作

package main
import ("fmt"
)func main() {a,b := 1,0   // variable a & b are declared and initializedresult := a/b        // division operationfmt.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]) commentedfmt.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捕获的错误处理代码能够执行。

相关内容

热门资讯

相亲闪婚后未办婚礼未同居,男子... 近日,湖南省汨罗市人民法院审理了一起婚约财产纠纷案件。 2024年4月初,王某与张某(女)通过某婚姻...
韩独检组下周将同时起诉尹锡悦夫... 据中国新闻网援引韩联社21日报道,负责调查韩国前总统尹锡悦夫人金建希弊案的独立检察组(独检组)将于下...
对毒品犯罪被告人适用死刑,应考... 如果您想第一时间收到我的更新,请点开文章标题下面的蓝色字体的“刑事专业律师何忠民”,再点击右上角,然...
一财社论:海南封关为制度型开放... 12月18日,海南自由贸易港正式启动封关运作。封关后,海南岛全岛将建成一个海关监管特殊区域,实施以“...
石家庄市住建局:制度筑基 科技... 石家庄发布(shijiazhuangfabu) 运营|石家庄广播电视台新媒体中心 来源|石家庄新闻 ...
长安汽车获国内首块L3级自动驾... 极目新闻记者 邓波 12月20日,国内首块L3级自动驾驶专用正式号牌“渝AD0001Z”在重庆诞生,...
祁阳卫健局回应“手术钻头遗留患... 近日,湖南祁阳市中医医院发生骨科手术钻头断裂遗留患者体内事件,引发公众关注。12月21日,南都N视频...
相亲闪婚后未办婚礼未同居,男子... 近日,湖南省汨罗市人民法院审理了一起婚约财产纠纷案件。 2024年4月初,王某与张某(女)通过某婚姻...
“手术钻头断裂遗留患者体内”,... 12月21日,湖南祁阳市卫生健康局发布情况通报: 近日,有媒体报道祁阳市中医医院发生骨科手术钻头断裂...
债务逾期13亿元!因借款合同纠... 12月21日晚间,万通发展(SH 600246)发布公告称,公司控股股东嘉华东方控股(集团)有限公司...