Go语言的处理错误

读取文件时处理错误,程序清单如下:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值