读取文件时处理错误,程序清单如下:
package main
import(
"fmt"
"io/ioutil"
)
func main(){
file, err:=ioutil.ReadFile("foo.txt")
if err!=nil{
fmt.Println(err)
return
}
fmt.Println("%s",file)
}
运行结果如下:
open foo.txt: no such file or directory
创建并打印错误,程序清单如下:
package main
import(
"fmt"
"errors"
)
func main(){
err:=errors.New("Something went wrong")
if err!=nil{
fmt.Println(err)
}
}
运行结果如下:
Something went wrong
设置错误的格式,程序清单如下:
package main
import(
"fmt"
)
func main(){
name,role:="Richard Jupp","Drummer"
err:=fmt.Errorf("The %v %v quit.",role,name)
if err!=nil{
fmt.Println(err)
}
}
运行结果如下:
The Drummer Richard Jupp quit.
从函数返回错误,程序清单如下:
package main
import(
"fmt"
)
func Half(numberToHalf int)(int,error){
if numberToHalf%2!=0{
return -1,fmt.Errorf("Cannot half %v",numberToHalf)
}
return numberToHalf/2,nil
}
func main(){
n,err:=Half(19)
if err!=nil{
fmt.Println(err)
return
}
fmt.Println(n)
}
运行结果如下:
Cannot half 19
使用panic来停止执行程序,程序清单如下:
package main
import(
"fmt"
)
func main(){
fmt.Println("This is executed")
panic("Oh no. I can do no more. Goodbye.")
fmt.Println("This is not executed")
}
运行结果如下:
This is executed
panic: Oh no. I can do no more. Goodbye.
goroutine 1 [running]:
main.main()
/Users/douxiaobo/go/src/main/main.go:8 +0x65
exit status 2
在下面的情形下,使用panic可能是正确的选择:
程序处于无法恢复的状态。这可能意味着无路可走了,或者再往下执行程序将带来更多的问题。在这种情况下,最佳的选择是让程序崩溃。
发生了无法处理的错误。
error界面
代码如下:
package main
import (
"fmt"
)
type Err struct{}
func (_ *Err) Error() string {
return "To err is human"
}
func ToErr(ok bool) error {
var e *Err = nil
if ok {
e = &Err{}
}
return e
}
func NoErr(ok bool) error {
if !ok {
return &Err{}
}
return nil
}
func main() {
fmt.Println(ToErr(true))
fmt.Println(ToErr(false))
fmt.Println(NoErr(true))
fmt.Println(NoErr(false))
}
运行结果如下:
To err is human
To err is human
<nil>
To err is human
错误类型(error)
写法如下:
type error interface{
Error() string
}
panic:
在Go语言中,执行错误会触发运行时异常,即panic,相当于使用实现了接口类型runtime.Error调用内置函数panic()。运行时,异常用来表示 非常严重的不可恢复的错误。
panic的写法如下:
func panic(interface{})
必须先声明defer,才能在defer修饰的函数中捕获到(recover)异常。
一般不能随意用panic()来中止程序,必须尽力补求异常和错误以便让程序能继续执行。
在自定义包中需要做好错误处理和异常处理,这是所有自定义包都应用遵守的规则。
(1)在包内部,应该用recover()对运行时异常进行捕获。
(2)向包的调用者返回错误值(而不是直接发出异常)。
代码如下:
package main
import (
"fmt"
)
func div(a, b int) {
defer func() {
if r := recover(); r != nil {
fmt.Printf("捕获到错误:%s\n", r)
}
}()
if b < 0 {
panic("除数需要大于0")
}
fmt.Println("余数为:", a/b)
}
func main() {
// 捕捉内部的Panic错误
div(10, 0)
// 捕捉主动Panic的错误
div(10, -1)
}
运行结果如下:
[Running] go run "c:\Program Files\Go\src\main.go"
捕获到错误:runtime error: integer divide by zero
捕获到错误:除数需要大于0
[Done] exited with code=0 in 22.431 seconds
recover:
recover()内建函数用于从异常或错误场景中恢复,让程序可以从异常中重新获得控制权,停止中止过程进而恢复正常执行。
recover的函数签名如下:
func recover() interface{}
recover()函数只能在defer修饰的函数中使用,用于取得异常传递过来的错误值。
异常会使栈被展开直到defer修饰的函数中的recover()被调用或者程序中止。
defer的项目规则:
规则一:defer声明时,其后面函数参数会被实时解析。
规则二:defer执行顺序为先进后出(FILO)。
规则三:defer可以读取函数的有名返回值。
规则一的代码如下:
package main
import "fmt"
func main() {
var i int = 1
// 规则一,当defer被声明时,其后面函数参数会被实时解析
// 注意,fmt.Println在defer后面,它的参数会实时计算
// 输出: result => 2 (而不是 4)
defer fmt.Println("result1 =>", func() int { return i * 2 }())
i++
// 下面defer后面的函数无参数,所以最里层的i应该是3
defer func() {
fmt.Println("result2 =>", i*2)
}()
i++
}
运行结果如下:
[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\tempCodeRunnerFile.go"
result2 => 6
result1 => 2
[Done] exited with code=0 in 6.327 seconds
规则二的代码如下:
package main
import "fmt"
func main() {
// 规则二 defer执行顺序为先进后出
defer fmt.Print(" !!! ")
defer fmt.Print(" world ")
fmt.Print(" hello ")
}
运行结果如下:
[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\main.go"
hello world !!!
[Done] exited with code=0 in 3.473 seconds
规则三的代码如下:
package main
import "fmt"
func fun1() (i int) {
// 规则三,defer可以读取有名返回值(函数指定了返回参数名)
defer func() {
i = i + 10 // defer可以读取有名返回值
}()
return 0 // 一般会认为返回0,实际上是10
}
func main() {
fmt.Println("result2 =>", fun1())
}
运行结果如下:
[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\main.go"
result2 => 10
[Done] exited with code=0 in 4.109 seconds
代码如下:
package main
import (
"fmt"
)
func main() {
fmt.Println("=========================")
fmt.Println("fun1 return:", fun1())
fmt.Println("=========================")
fmt.Println("fun2 return:", fun2())
fmt.Println("=========================")
fmt.Println("fun3 return:", fun3())
fmt.Println("=========================")
fmt.Println("fun4 return:", fun4())
}
func fun1() (i int) {
defer func() {
i++
fmt.Println("fun1 defer2:", i) // 打印结果为 fun1 defer2: 2
}()
// 规则二 defer执行顺序为先进后出
defer func() {
i++
fmt.Println("fun1 defer1:", i) // 打印结果为 fun1 defer1: 1
}()
// 规则三 defer可以读取有名返回值(函数指定了返回参数名)
return 0 //这里实际结果为2。如果是return 100呢
}
func fun2() int {
var i int
defer func() {
i++
fmt.Println("fun2 defer2:", i) // 打印结果为 fun2 defer2: 2
}()
defer func() {
i++
fmt.Println("fun2 defer1:", i) // 打印结果为 fun2 defer1: 1
}()
return i
}
func fun3() (r int) {
t := 5
defer func() {
t = t + 5
fmt.Println("fun3 defer:", t) // 打印结果为 fun3 defer: 10
}()
return t
}
func fun4() int {
i := 8
// 规则一 当defer被声明时,其参数会被实时解析
defer func(i int) {
fmt.Println("fun4 defer:", i) // 打印结果为 fun4 defer: 8
}(i)
i = 19
return i
}
运行结果如下:
[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\tempCodeRunnerFile.go"
=========================
fun1 defer1: 1
fun1 defer2: 2
fun1 return: 2
=========================
fun2 defer1: 1
fun2 defer2: 2
fun2 return: 0
=========================
fun3 defer: 10
fun3 return: 5
=========================
fun4 defer: 8
fun4 return: 19
[Done] exited with code=0 in 3.054 seconds
代码如下:
package main
import (
"fmt"
"time"
)
func main() {
defer timeCost(time.Now())
fmt.Println("start program")
time.Sleep(5 * time.Second)
fmt.Println("finish program")
}
func timeCost(start time.Time) {
terminal := time.Since(start)
fmt.Println(terminal)
}
运行结果如下:
[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\tempCodeRunnerFile.go"
start program
finish program
5.0009098s
[Done] exited with code=0 in 9.582 seconds