0

golang错误处理是使用return error的方式,虽然能返回错误但是没法返回错误码,比如java中的exception内有msg有error code

在golang项目如果写几个接口,接口返回值里面有error code ,但是golang 从内部函数调用中返回的error是不带code的,这就让错误码失去了意义,如果再包装一个exception结构体的话,return这个exception,但是感觉这样破坏了golang函数返回error的规则

有没有好的办法实现,没有 try catch 好麻烦

7月5日提问
7 个回答
1

go 1.14 将加如try 函数,期待ing.

1

自定义codemessage
将之组合起来,
自定义Error实现 json 的 MarshalJSON 方法 和 Error 方法

package main

import (
    "encoding/json"
    "fmt"
)

type Error struct {
    Code    int
    Message string
}

func (e Error) String() string {
    return ErrorCodes[e.Code]
}

func (e *Error) MarshalJSON() ([]byte, error) {
    return []byte(fmt.Sprintf(`{"code": %d, "message": "%s"}`, e.Code, e.String())), nil
}

var (
    ErrorUnauthorized = 401
)

var ErrorCodes = map[int]string{
    ErrorUnauthorized: "没有进行用户认证",
}

func main() {
    e := new(Error)
    e.Code = ErrorUnauthorized
    fmt.Println(e) // 没有进行用户认证
    b, err := json.Marshal(e)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(b)) // {"code":401,"message":"没有进行用户认证"}
}
0

golang 的 Error 是一个 interface ,你可以用任何复杂的类做 error ,包含你需要的所有的错误信息。

只要类里面有一个 Error() String 函数就可以了。

0

可以参考下 grpc 的实现, 把 status 包装成 error. 官方仓库里有个简单的例子: https://github.com/grpc/grpc-...

0
package main

import (
    "errors"
    "fmt"
)

const (
    UnknownErrorCode = -1
)

func New(code int, text string) error {
    return &ErrorCode{code, text}
}

type ErrorCode struct {
    code int
    s    string
}

func (e *ErrorCode) Error() string {
    return e.s
}

func (e *ErrorCode) Code() int {
    return e.code
}

func ErrorToErrorCode(err error) *ErrorCode {
    if err == nil {
        return nil
    }

    errorCode, ok := err.(*ErrorCode)
    if ok {
        return errorCode
    }

    return New(UnknownErrorCode, err.Error()).(*ErrorCode)
}

func main() {
    e1 := t1()
    e2 := t2()

    ec1 := ErrorToErrorCode(e1)
    ec2 := ErrorToErrorCode(e2)
    ec3 := ErrorToErrorCode(nil)

    fmt.Println(ec1.Code(), ec1.Error())
    fmt.Println(ec2.Code(), ec2.Error())
    fmt.Println(ec3)

}

func t1() error {
    return New(100, "test1")
}

func t2() error {
    return errors.New("test2")
}

程序输出:

100 test1
-1 test2
<nil>
0

error 只是一个接口,你的类型只要实现了 Error(),就可以作为 error 类型。在此基础上,你可以随意扩展。比如,定义两种类型错误,分别是 SystemError 和 UserError。

实现的时候,为它们增加成员属性 code 接口。前面其实已经有了类似的例子。比如

type SystemError struct {
    Code int
}

func (e SystemError) Error() string {
    return "系统错误,错误码 " + e.Code
}

UserError 同样可以这么处理,控制起来非常灵活简单。

0

标准库syscall中有一个Errno类型,就是一个系统错误码,加上自定义Error函数返回错误消息。可以参照一下。

首先定义一个错误码类型,底层用int就行了:

type ErrCode int

然后定义const错误码:

const (
    ERR_INVALID_PARAM ErrCode = 1 // 非法参数
    ERR_INVALID_COOKIE ErrCode = 2 // 无效cookie
    // ...
)

每个错误码后通过注释添加描述,然后使用go generate + stringer自动生成错误码与错误消息的对照:

//go:generate stringer -type=ErrCode --linecomment

生成文件errcode_string.go

// Code generated by "stringer -type=ErrCode --linecomment"; DO NOT EDIT.

package code

import "strconv"

const _ErrCode_name = "无效参数无效cookie"

var _ErrCode_index = [...]uint8{0, 12, 24}

func (i ErrCode) String() string {
    i -= 1
    if i < 0 || i >= ErrCode(len(_ErrCode_index)-1) {
        return "ErrCode(" + strconv.FormatInt(int64(i+1), 10) + ")"
    }
    return _ErrCode_name[_ErrCode_index[i]:_ErrCode_index[i+1]]
}

我们再为ErrCode实现error接口就ok了啊:

func (e ErrCode) Error() string {
    return e.String()
}

现在就可以把ErrCode类型传给error接口了。

go generate可以放在项目打包脚本中执行。

测试:

package main

import (
    "fmt"

    "github.com/darjun/code" // 这是我的包,替换一下
)

func main() {
    var a error = code.ERR_INVALID_PARAM
    fmt.Println(a)
    // 输出:无效参数

    var b error = code.ERR_INVALID_COOKIE
    fmt.Println(b)
    // 输出:无效cookie
}

撰写答案

推广链接