10.2 错误处理-函数返回错误、可用性与恐慌

从函数中返回错误

从函数中返回的错误值除了携带关于错误的描述信息以外,还可以将错误发生的位置时间环境等上下文信息一并提供给函数调用者,快速诊断故障。

Go语言处理错误的方式具有显著的优点:

  • 函数中发现的错误并不在函数中处理,而是在调用该函数的地方。这为错误处理提供了极大的灵活性,将更多主动权交给函数使用者,而不是由其缔造者自以为是地越俎代庖。
  • 以返回错误值而非抛出异常的方式宣告错误,给函数调用者以更大的自由度,毕竟处理不处理错误以及怎样处理错误,应该由函数的用户说了算,一切强加的都是违背人性的。
  • 每次调用函数或方法都做错误检查,这种做法看似繁琐,但错误可像其它任何类型的数据一样在函数之间传递,对它们的控制会更加简单而且直接,这意味着代码会更加简洁。
// 从函数中返回错误
// 标准库中的error是一个接口
// 
// type error interface {
//     Error() string
// }
//
// 通过实现该接口,可以自定义错误信息的内容和格式
// 
// func (err 自定义错误类型) Error() string {
//     return 错误信息字符串
// } 
package main

import (
    "fmt"
    "runtime"
)
// 自定义错误类型
type detailedError struct {
    file string	// 记录引发错误的源文件
    line int 		// 记录引发错误的行号
    desc string	// 给出错误的具体描述
}
// 为自定义错误类型实现error接口中的Error方法
func (err detailedError) Error() string {
    return fmt.Sprintf("%v:%v> %v",		// 错误创建方法2
        err.file, err.line, err.desc)
}
// 返回自定义错误类型的构造函数
func newError(pc uintptr, file string,
    line int, ok bool) func(desc string) error {
    return func(desc string) error {
        return detailedError{file, line, desc}
    }
}

// 可能出现问题的函数
func half(n int) (int, error) {
    if n%2 != 0 {
        return -1, newError(runtime.Caller(0))(	// 返回调用点的上下文信息
            fmt.Sprintf("Unable to half %v", n))
    }

    return n / 2, nil
}
func main() {
    h, err := half(19)
    if err != nil {
        fmt.Println(err)
		// G:/GoWorkspace/src/error/return/main.go:47> Unable to half 19
        return
    }


    fmt.Println(h) 
}

错误与可用性

除了从纯技术角度考虑有关错误的产生和处理方式以外,还需站在用户的立场上做更加精细的设计。毕竟所编写的库或者包是提供给他人使用的,其中错误系统的合理性和有效性,将极大地影响到库或者包的可用性用户体验

向用户报告错误不是为了推卸责任,而是为了提供真正有价值的帮助,例如:

  • 哪里出现了问题?
  • 出现了什么问题?
  • 为什么会出问题?
  • 应如何解决问题?

如果从库或者包中能够获得形式一致且真正有用的错误信息,用户从错误中恢复的可能性就会更高,并因此坚信这样的库或者包不仅有用而且值得信赖。

恐慌

panic是Go语言的内置函数,调用它将立即终止当前运行的程序并引发恐慌。

  • panic("Oh no, I can do no more. Goodbye")

panic函数不会返回,在其将参数字符串打印出来以后程序即刻崩溃,系统会打印出更多详细信息。

恐慌通常意味着很严重的问题,调用panic函数实是无奈之举,应被视为一种没有办法的办法,因此千万不要滥用。出现以下情形引发恐慌是合理的:

  • 程序已经处于无法恢复的状态,如果继续运行只会带来更多更严重的问题。
  • 发生了无法处理的错误,无论做什么都存在风险,最好还是什么都不要做。
// 引发恐慌
// 内置函数panic可引发恐慌并令程序停止运行
 2 
 3 package main
 4
 5 import "fmt"
 6
 7 func foo() {
 8     panic("Oh no, I can do no more. Goodbye")
 9 }
10
11 func main() {
12     fmt.Println("This is executed")
13
14     foo()
15
16     fmt.Println("This is not executed")	// 未执行
17 }
//	This is executed
// 	panic: Oh no, I can do no more. Goodbye

//	goroutine 1 [running]:
//	main.foo(...)
//   E:GoWorkSpace/src/error/panic/main.go:8 main.main()
//   E:GoWorkSpace/src/error/panic/main.go:14 +0x80
// 	exit status 2 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值