Go语言中的错误处理系统

来源:互联网 发布:c语言怎么写窗口程序 编辑:程序博客网 时间:2024/06/09 19:45

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 mainimport "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这样格式化输入来生成errfmt包提供了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。

0 0