Go语言中的错误处理系统
原文链接:http://blog.csdn.net/cc7756789w/article/details/51014076
作者:牧歌
github:https://github.com/ZhangHang-z
转载请注明出处,未经作者允许不可用于商业目的。
侵入式接口和Go的非侵入式接口
Go语言中没有其他语言try....catch
的语法,因为Go语言的特殊的接口类型,不需要侵入式地去实现接口,自定义错误类更为简单。
先来介绍Go中接口的使用方法,需要理解一个概念:Go中任何实现了某个接口所定义函数的类都可以被赋值给接口类型。
先来看一下Java中是怎么实现接口的:
public interface Bird {
void fly()
boolean haveFeather()
}
public interface Animal {
void run()
}
// 侵入式实现接口
public class Little implements Animal, Bird {
@Override
public void run() {
System.out.println("running...")
}
@Override
public void fly() {
System.out.println("I'm flying...")
}
@Override
public boolean haveFeather() {
return true
}
}
Go是这样实现的:
import "fmt"
type Human struct {
name string
age uint8
}
func (h *Human) PrtCountry(c string) error {
fmt.Printf("%s was %d years old, and he from %s\n", h.name, h.age, c)
return nil
}
func (h *Human) PrtLang(lang string) error {
fmt.Printf("%s was %d years old, and he speak %s\n", h.name, h.age, lang)
return nil
}
type China interface {
PrtCountry(c string) error
}
func main() {
var person1 *Human = &Human{"bob", 22}
person1.PrtCountry("Wuxi")
var person2 China = person1
person2.PrtCountry("Suzhou")
}
>>> [ `go run errors_test1.go` | done: 971.446272ms ]
>>> bob was 22 years old, and he from Wuxi
>>> bob was 22 years old, and he from Suzhou
我们看到,Go只需要把一个实现了接口所需函数的对象赋值给对象类型就可以,当然我举得例子并不恰当,另外关于指针对象和值对象的区别请自行阅读书籍或文档。
error接口的定义
下面我们来直入主题,错误处理是一门优秀的语言必不可缺的,那么Go中是如何实现的呢?
查看官网的语言定义Expressions Errors上我们发现:
(额,万恶的XXX,如果打不开可以在命令行输入godoc -http ":9999"
然后浏览器中输入127.0.0.1:999
打开godoc内置的文档服务器,Win和Linux一样)
我的英文也不咋的,大概是说:
// 预先声明类型error被定义为:
type error interface {
Error() string
}
// 这个约定俗成的接口用来表现出一个error条件
// 返回nil表示没有发生error
// 下面是一个函数返回error的用法....
func Read(f *File, b []byte) (n int, err error)
error
接口的定义非常简洁,你只需要实现Error函数就可以自定义一个Error处理类,我们来自定义一个error类型:
package main
import "fmt"
type MyError struct {
errString string
}
func (e MyError) Error() string {
return e.errString
}
func outError() error {
return MyError{
"Always this, fuck my Error.",
}
}
func main() {
if err := outError(); err != nil {
fmt.Println(err)
}
}
>>> [ `go run error_test2.go` | done: 857.997463ms ]
>>> Always this, fuck my Error.
刚才我们讲过接口赋值,如果你明白了接口赋值是怎么工作,那么不难理解为什么可以这样返回error类型,其实就相当于做了如下工作:
var err error = MyError{"Always this, fuck my Error."}
return err
(当然这里的err传递的都是值语义,并非引用)
这个例子在errors文档也有Example
标准库errors.go
errors.go标准库的源码只有几行,其中给我们封装了一个建议的错误处理函数:
// Package errors implements functions to manipulate errors.
package errors
// New returns an error that formats as the given text.
func New(text string) error {
return &errorString{text}
}
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
这个New方法的作用你可以比作为工厂函数,利用它我们不必自己再重复写自定义错误类来赋值给error接口。
func main() {
err := errors.New("Fuck my error")
if err != nil {
fmt.Println(err)
}
}
>>> Fuck my error
如果我们需要使用%s %d这样格式化输入来生成err
fmt包提供了Errorf
函数:
const eName, id = "Internal Error", "12345"
func main() {
err := fmt.Errorf("Error: %s occured, time: %s", eName, id)
if err != nil {
fmt.Println(err)
}
}
总结
Go中只要实现了Error函数的类都可以赋值给error接口,没有错误只需要返回nil。