Go 语言使用一个独立的·明确的返回值来传递错误信息的。这与使用异常的 Java 和 Ruby 以及在 C 语言中经常见到的超重的单返回值/错误值相比,

Go 语言的处理方式能清楚的知道哪个函数返回了错误,并能像调用那些没有出错的函数一样调用。

错误和异常

  • 错误:指的是可能出现问题的地方出现了问题;

    比如打开一个文件时失败,这种情况在人们的意料之中 ;

  • 异常:指的是不应该出现问题的地方出现了问题;

    比如引用了空指针,这种情况在人们的意料之外。可见,错误是业务过程的一部分,而异常不是 。

Golang中引入error接口类型作为错误处理的标准模式,如果函数要返回错误,则返回值类型列表中肯定包含error。

error处理过程类似于C语言中的错误码,可逐层返回,直到被处理。

案例

package main

import (
"errors"
"fmt"
) // 按照惯例,错误通常是最后一个返回值并且是 error 类型,一个内建的接口。
func f1(arg int) (int, error) {
if arg == 42 {
// errors.New 构造一个使用给定的错误信息的基本error 值。
return -1, errors.New("can't work with 42")
} // 返回错误值为 nil 代表没有错误。
return arg + 3, nil
} // 通过实现 Error 方法来自定义 error 类型是可以的。这里使用自定义错误类型来表示上面的参数错误。
type argError struct {
arg int
prob string
} func (e *argError) Error() string {
return fmt.Sprintf("%d - %s", e.arg, e.prob)
} func f2(arg int) (int, error) {
if arg == 42 {
// 使用 &argError 语法来建立一个新的结构体,并提供了 arg 和 prob 这个两个字段的值。
return -1, &argError{arg, "can't work with it"}
}
return arg + 3, nil
} func main() { // 下面的两个循环测试了各个返回错误的函数。注意在 if行内的错误检查代码,在 Go 中是一个普遍的用法。
// range 提供每项的索引和值。我们不需要索引,所以们使用空值定义符_来忽略它。有时候是需要这个索引的。
for _, i := range []int{7, 42} {
if r, e := f1(i); e != nil {
fmt.Println("f1 failed:", e)
} else {
fmt.Println("f1 worked:", r)
}
}
for _, i := range []int{7, 42} {
if r, e := f2(i); e != nil {
fmt.Println("f2 failed:", e)
} else {
fmt.Println("f2 worked:", r)
}
} // 你如果想在程序中使用一个自定义错误类型中的数据,你需要通过类型断言来得到这个错误类型的实例。
_, e := f2(42)
if ae, ok := e.(*argError); ok {
fmt.Println(ae.arg)
fmt.Println(ae.prob)
}
}

输出结果:

f1 worked: 10
f1 failed: can't work with 42
f2 worked: 10
f2 failed: 42 - can't work with it
42
can't work with it

Golang中引入两个内置函数panic (['pænɪk]恐惧)和recover ([.ri'kʌvər]恢复)来触发和终止异常处理流程,同时引入关键字defer([dɪ'fɜr])来延迟执行defer后面的函数。

Panic

panic 意味着有些出乎意料的错误发生。通常我们用它来表示程序正常运行中不应该出现的,或者我们没有处理好的错误。

import "os"

func main() {

	// 我们将使用 panic 来检查预期外的错误。这个是为 panic 准备的例子。
panic("a problem") // panic 的一个基本用法就是在一个函数返回了错误值但是我们并不知道(或者不想)处理时终止运行。
// 这里是一个在创建一个新文件时返回异常错误时的panic 用法。
_, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
}
输出:
panic: a problem goroutine 1 [running]:
main.main()
/.../panic.go:10 +0x45

Defer

Defer 被用来确保一个函数调用在程序执行结束前执行。同样用来执行一些清理工作。 defer 用在像其他语言中的 ensure 和 finally用到的地方。

假设我们想要创建一个文件,向它进行写操作,然后在结束时关闭它。这里展示了如何通过 defer 来做到这一切。

import (
"fmt"
"os"
) func main() {
// 在 closeFile 后得到一个文件对象,我们使用 defer通过 closeFile 来关闭这个文件。
// 这会在封闭函数(main)结束时执行,就是 writeFile 结束后。
f := createFile("defer.txt")
defer closeFile(f)
writeFile(f)
} func createFile(p string) *os.File {
fmt.Println("creating")
f, err := os.Create(p)
if err != nil {
panic(err)
}
return f
} func writeFile(f *os.File) {
fmt.Println("writing")
fmt.Fprintln(f, "data")
} func closeFile(f *os.File) {
fmt.Println("closing")
f.Close()
}
输出:
creating
writing
closing

明显,这个文件在写入后是已关闭的。

使用 defer+recover 来处理错误

import (
"fmt"
) func main() {
// 使用defer + recover来捕获和处理异常
defer func() {
// recover 是内置函数,可以捕获异常
err := recover()
if err != nil {
fmt.Println("err=", err)
}
}()
num1 := 10
num2 := 0
res := num1 / num2
fmt.Println("res=", res)
}
输出:
err= runtime error: integer divide by zero

参考文章:

[Golang]-4 错误处理、Panic、Defer的更多相关文章

  1. Golang错误处理函数defer、panic、recover、errors.New介绍

    在默认情况下,当发生错误(panic)后,程序就会终止运行 如果发生错误后,可以捕获错误,并通知管理人员(邮件或者短信),程序还可以继续运行,这当然无可厚非 errors.New("错误信息 ...

  2. 【GoLang】panic defer recover 深入理解

    唉,只能说C程序员可以接受go的错误设计,相比java来说这个设计真的很差劲! 我认为知乎上说的比较中肯的: 1. The key lesson, however, is that errors ar ...

  3. 『GoLang』错误处理

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

  4. [golang note] 错误处理

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

  5. GoLang之错误处理

    错误处理 error Go语言引入了一个错误处理的标准模式,即error接口,该接口定义如下: type error interface { Error() string } 对于大多数函数,如果要返 ...

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

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

  7. golang error错误处理

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

  8. 解决Ubuntu启动错误——kernel panic not syncing vfs unable to mount root fs on unknown-block 0 0 – error

    最近在倒腾Ubuntu,然后想着怎么美化一下界面,于是照着网上的教程整了一下Flatabulous这个软件,然后好像/boot就满了.关机之后再开机就出现了如题所述的错误,无法开机,也无法进入reco ...

  9. golang处理错误的艺术

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

随机推荐

  1. 开发中经常使用到的Xcode快捷键

    工欲善其事必先利其器. 有了这些快捷键加持,你写代码不仅很6而且还很好看. 这些快捷键都是平时使用频率非常高的,今天整理出来分享给大家了. 左缩进:Cmd + [ 右缩进:Cmd + ] 代码格式化/ ...

  2. HDFS HBase Solr Which one? 从访问模式角度决策

    HDFS 压缩性能最优.扫描速度最快:不支持随机访问,仅支持昂贵.复杂的文件查询 HBase适合随机访问 Solr 适合检索需求 HBase访问单个记录的时间为毫秒级别,而HDFS不支持随机访问. H ...

  3. CAP理论解读

    经历过技术面试的小伙伴想必对这个两个概念已经再熟悉不过了! 我当年参加面试的时候,不夸张地说,只要问到分布式相关的内容,面试官几乎是必定会问这两个分布式相关的理论. 并且,这两个理论也可以说是小伙伴们 ...

  4. copy,集合

    一.基础数据类型补充: 1种方法:删除列表里面的元素时,一定不能循环列表,会出错.可以循环索引,然后循环删除开头或结尾这个位置的元素(原开头结尾的元素被删除之后,会有新的元素顶上来). 2种方法:把要 ...

  5. Golang简易版 网站路径扫描demo

    package main import ( "bufio" "fmt" "net/http" "os" "re ...

  6. nginx、apache比较

    Nginx:异步,多个连接(万级别)可以对应一个进程 轻量级,采用 C 进行编写,同样的 web 服务,会占用更少的内存及资源 抗并发,nginx 以 epoll and kqueue 作为开发模型, ...

  7. Flutter环境搭建遇坑小结(一)

    对flutter的了解与开发也有一段时间了,总的来说,搭建开发环境遇到的各种坑也是很多,尤其对于初次接触Android开发的人员来说 一.flutter运行提示Running Gradle task ...

  8. 五:Spring Security 中的角色继承问题

    Spring Security 中的角色继承问题 以前的写法 现在的写法 源码分析 SpringSecurity 在角色继承上有两种不同的写法,在 Spring Boot2.0.8(对应 Spring ...

  9. JDBC的操作步骤和实例()

    加载JDBC驱动程序 提供JDBC连接的URL 创建数据库的连接 创建一个Statement 执行SQL语句 处理结果 关闭JDBC对象 实例JdbcUtils 创建一个JDBC程序包含7个步骤: 1 ...

  10. 并发编程(Process对象的join方法)(

    一. Process对象的join方法 在主进程运行过程中如果想并发地执行其他的任务,我们可以开启子进程,此时主进程的任务与子进程的任务分两种情况 情况一:在主进程的任务与子进程的任务彼此独立的情况下 ...