如果函数实现过程中,如果出现不能处理的错误,可以返回给调⽤者处理。⽐如我们调⽤标准库函数 os.Open 读取⽂件
os.Open 有 2 个返回值,第⼀个是 *File ,第⼆个是 error如果调⽤成功, error 的值是 nil => nil 是⼀个空值如果调⽤失败,例如⽂件不存在,将返回⼀个⾮空 error 。我们可以通过 error 知道具体的错误信息。
package main
import "fmt"
import "os"
func main() {
fmt.Println("vim-go")
_, err := os.Open("a.txt")
if err != nil {
fmt.Println("出错啦")
fmt.Println(err)
}
}
[root@localhost src]# go run error.go
vim-go
出错啦
open a.txt: no such file or directory
可以通过 errors.New 返回⾃定义的错误
package main
import "fmt"
import "os"
import "errors"
func main() {
fmt.Println("vim-go")
_, err := os.Open("a.txt")
if err != nil {
fmt.Println("出错啦")
fmt.Println(err)
}
}
func myprint(name string) error {
if len(name) == 0 {
return errors.New("error: name is null")
}
fmt.Println(name)
return nil
}
[root@localhost src]# go run error.go
vim-go
出错啦
open a.txt: no such file or directory
defer有延迟的意思,就是稍后执⾏,先执⾏函数主体内容,defer的内容稍后执⾏主体内容执⾏完毕后,defer的内容按照调⽤顺序的 相反顺序 逐个执⾏defer 的执⾏⽅式类似其他语⾔中的 析构函数 即使函数发⽣ 严重错误 也会执⾏常⽤于 资源清理、⽂件关闭、解锁以及记录时间 等操作⽀持匿名函数的调⽤通过与匿名函数配合可在return之后 修改 函数计算结果如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷⻉,否则则是引⽤某个变量的地址
示例:使用defer关键字
func main() {
fmt.Println("main_a")
defer fmt.Println("deffer_a")
fmt.Println("main_b")
defer fmt.Println("deffer_b")
fmt.Println("main_c") }
# go run func.go
main_a
main_b
main_c
deffer_b
deffer_a
panic英⽂意思是恐慌,在这⾥意思是抛出⼀个程序异常,即报告程序运⾏时错误当在⼀个函数执⾏过程中调⽤ panic() 函数时,正常的函数执⾏流程将⽴即终⽌,可以理解为 Throw之前使⽤ defer 关键字延迟执⾏的语句将正常展开执⾏,并导致逐层向上执⾏ panic 流程直⾄所属的 goroutine 中所有正在执⾏的函数被终⽌。错误信息将被报告,包括在调⽤ panic() 函数时传⼊的参数,这个过程称为错误处理流程。
package main
import "fmt"
func main(){
defer fmt.Println("deferred main")
sayHi("")
}
func sayHi(name string){
defer fmt.Println("deferred sayHi")
if len(name)<1{
panic("hahaha")
}
fmt.Println("hi", name)
fmt.Println("bla,bla")
}
输出结果
deferred sayHi
deferred main
panic: hahaha
goroutine 1 [running]:
main.sayHi({0x0?, 0x60?})
/Users/beebol/golearn/c.go:13 +0x149
main.main()
/Users/beebol/golearn/c.go:7 +0x74
exit status 2
执⾏过程:执⾏到 panic("hahaha") 时,程序控制权交给defer⾸先 sayHi ⽅法中的 defer 被执⾏,输出: deferred sayHi接着,从 sayHi ⽅法返回到main ⽅法中的 defer 被执⾏,输出: deferred main最后,调⽤返回到顶层函数,然后将错误消息和堆栈信息打印出来。
recover() 函数⽤于终⽌错误处理流程,也就是我们常规说的 catch。recover() 应该在⼀个使⽤ defer 关键字的函数中执⾏,以有效截取错误处理流程。Panic 可以在任何地⽅引发,但 recover 只有在 defer 调⽤的函数中有效如果没有在发⽣异常的 goroutine 中明确调⽤恢复过程(使⽤ recover 关键字),会导致该 goroutine 所属的进程打印异常信息后直接退出。
示例:
package main
import "fmt"
func main(){
sayHi("")
fmt.Println("end!!")
}
func sayHi(name string){
arr := []int{1,2,3}
defer recoverSayHi()
if len(name)<1{
fmt.Println(arr[5])
// panic("hahaha")
}
fmt.Println("hi", name)
fmt.Println("bla,bla")
}
func recoverSayHi(){
fmt.Println("you can clean")
if r := recover(); r!=nil{
fmt.Println("recoved from", r)
}
}
执⾏过程调⽤sayHi函数,recoverSayHi() 被延迟执⾏sayHi中遇到异常/调⽤panic,触发defer recoverSayHirecoverSayHi中的 recover() 捕捉到了这个异常,并停⽌了异常继续向上抛它调⽤了 recover(),并接收到 panic 的错误信息。