错误处理

error

Go语言引入了一个错误处理的标准模式,即error接口,该接口定义如下:

type error interface {
Error() string
}

对于大多数函数,如果要返回错误,可以将error作为多返回值的最后一个:

func foo(param int)(ret int, err error)
{
...
}

调用时的代码:

n, err := foo(0)
if err != nil {
// 错误处理
} else {
// 使用返回值n
}

我们还可以自定义错误类型,一个例子:

package main

import "fmt"
import "errors" //自定义的出错结构
type myError struct {
arg int
errMsg string
}
//实现Error接口
func (e *myError) Error() string {
return fmt.Sprintf("%d - %s", e.arg, e.errMsg)
} //两种出错
func error_test(arg int) (int, error) {
if arg < 0 {
return -1, errors.New("Bad Arguments - negtive!")
}else if arg >256 {
return -1, &myError{arg, "Bad Arguments - too large!"}
}
return arg*arg, nil
} //相关的测试
func main() {
for _, i := range []int{-1, 4, 1000} {
if r, e := error_test(i); e != nil {
fmt.Println("failed:", e)
} else {
fmt.Println("success:", r)
}
}
}

defer

你可以在Go函数中添加多个defer语句,当函数执行到最后时,这些defer语句会按照逆序执行(即最后一个defer语句将最先执行),最后该函数返回。

特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题。如下代码所示,我们一般写打开一个资源是这样操作的:

func CopyFile(dst, src string) (w int64, err error) {
srcFile, err := os.Open(src)
if err != nil {
return
} defer srcFile.Close() dstFile, err := os.Create(dst)
if err != nil {
return
} defer dstFile.Close() return io.Copy(dstFile, srcFile)
}

如果defer后面一条语句干不完清理工作,也可以使用一个匿名函数:

defer func(){
...
}()

注意,defer语句是在return之后执行的,例如:

func test() (result int) {
defer func() {
result = 12
}()
return 10
} func main() {
fmt.Println(test()) // 12
}

panic() recover()

panic()函数用于抛出异常,recover()函数用于捕获异常,这两个函数的原型如下:

func panic(interface{})
func recover() interface{}

当在一个函数中调用panic()时,正常的函数执行流程将立即终止,但函数中之前使用defer关键字延迟执行的语句将正常展开执行,之后该函数将返回到调用函数,并导致逐层向上执行panic()流程,直至所属的goroutine中所有正在执行的函数被终止。错误信息将被报告,包括在调用panic()函数时传入的参数,这个过程称为错误流程处理。

panic()接受一个interface{}参数,可支持任意类型,例如:

panic(404)
panic("network broken")
panic(Error("file not exists"))

在defer语句中,可以使用recover()终止错误处理流程,这样可以避免异常向上传递,但要注意recover()之后,程序不会再回到panic()那里,函数仍在defer之后返回。

func foo() {
panic(errors.New("i'm a bug"))
return
} func test() (result int) {
defer func() {
if r := recover(); r != nil {
err := r.(error)
fmt.Println("Cache Exception:", err)
}
}()
foo()
return 10
} func main() {
fmt.Println(test()) // 0
}

注意,在一个函数中panic被调用后,其defer语句仍会执行,

func foo()(n int) {
defer func() {
if r := recover(); r != nil {
n++ // take effective
}
}()
n++ // take effective
panic(errors.New("i'm a bug"))
n++ // take no effective
return n
}

GoLang之错误处理的更多相关文章

  1. 个人犯的一个golang routine错误

    这个其实不是错误,2个写法没有区别.-2015.11.22 认识golang也不少时间了,也做过几个项目.最近发现之前用golang写的一个服务,内存涨得比较快,一直没找出来原因来.今天把疑惑发到群里 ...

  2. [golang note] 错误处理

    错误处理 • 错误处理的标准模式 √ golang错误处理的标准模式:error接口. √ golang函数如果要返回错误,规范上是将error作为多返回值中的最后一个,但这并非是强制要求. ▶ er ...

  3. [Golang]-4 错误处理、Panic、Defer

    目录 错误和异常 案例 Panic Defer 使用 defer+recover 来处理错误 参考文章: Go 语言使用一个独立的·明确的返回值来传递错误信息的.这与使用异常的 Java 和 Ruby ...

  4. golang处理错误的艺术

    golang中关键API的调用都会在最后返回err(golang多值返回). 调用者可以选择处理, 或者不处理该err, 或原装返回给上一层的调用者. golang中的err是error类型, typ ...

  5. Go_19: Golang 中错误与异常需要重新认识

    如何进行错误处理,这是一个Go程序员之间,特别是一些新的Go程序员,会经常讨论的问题.讨论到最后往往由于以下代码的多次出现而变成了抱怨. if err != nil { return err } 我们 ...

  6. Golang 中错误与异常需要重新认识

    如何进行错误处理,这是一个Go程序员之间,特别是一些新的Go程序员,会经常讨论的问题.讨论到最后往往由于以下代码的多次出现而变成了抱怨. if err != nil { return err } 我们 ...

  7. golang error错误处理

    error定义 数据结构 go语言error是一普通的值,实现方式为简单一个接口. // The error built-in interface type is the conventional i ...

  8. 『GoLang』错误处理

    Go 没有像 Java 和 .NET 那样的 try/catch 异常机制:不能执行抛异常操作.但是有一套 defer-panic-and-recover 机制. Go 的设计者觉得 try/catc ...

  9. golang常见错误

    import import unuse package: error : imported and not used: "os" := = c := 1 // error non- ...

随机推荐

  1. 如何绘制UML图?

    首先推荐在线绘制UML的网址:https://www.processon.com/,很好用. 在软件开发过程中,开发人员往往需要通过绘制类图来理清业务的实现思路,从而方便代码实现,也便于后期的代码维护 ...

  2. vmware ubuntu重置root密码

    1.重启ubuntu,按住shift(开机启动时) 2.选择recovery mode,enter 3.root选择root drop to root shell prompt 4.进入shell界面 ...

  3. Stack [NOIP模拟] [组合数学经典]

    Description栈是常用的一种数据结构,有n个元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列.你已经知道栈的操作有两种: push 和 pop ,前者是将一个元素进栈,后者是将栈顶元素弹出.现 ...

  4. PAT Basic 1005

    1005 继续(3n+1)猜想 (25 分) 卡拉兹(Callatz)猜想已经在1001中给出了描述.在这个题目里,情况稍微有些复杂. 当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程 ...

  5. web.config中的ExtensionlessUrlHandler-Integrated-4.0

    对于像MVC这种比较特殊的URL,例如 www.store.com/books/GetById/2 因为没有文件后缀名,IIS通常会无法解析,返回403或者404错误.ASP.NET v4.0增加了新 ...

  6. vue要点记录(待更新)

    Vue实例 每个 Vue 实例都会代理其 data 对象里所有的属性:vm.a===data.a //true 注意只有这些被代理的属性是响应的. 如果在实例创建之后添加新的属性到实例上,它不会触发视 ...

  7. JS_高程3.基本概念(4)操作符

    ECMA-262用于操作数据值的操作符包括: 算术操作符 位操作符 关系操作符 相等操作符 ECMAScript操作符的不同之处在于:它能够适用于很多值,包括字符串,数字值,布尔值,甚至是对象.(在应 ...

  8. hdu3466 Proud Merchants(01背包)

    https://vjudge.net/problem/HDU-3466 一开始想到了是个排序后的背包,但是排序的策略一直没对. 两个物品1和2,当p1+q2>p2+q1 => q1-p1& ...

  9. Docker技术快速精通指南

    doctor专业网站:http://www.dockerinfo.net/ Docker中文文档 csdn 的docker专栏: Docker技术快速精通指南

  10. 旋转矩阵(Rotation Matrix)的推导及其应用

    向量的平移,比较简单. 缩放也较为简单 矩阵如何进行计算呢?之前的文章中有简介一种方法,把行旋转一下,然后与右侧对应相乘.在谷歌图片搜索旋转矩阵时,看到这张动图,觉得表述的很清晰了. 稍微复杂一点的是 ...