error
类型是一个接口,只有一个
Error()
方法,但它对于
json
包并不特殊(
Error()
方法不会在其上调用)。
然而,
error
值可能保存可以很好地进行编组的静态类型的值,或者它们可以通过实现
json.Marshaler
来定义自己的编组逻辑。仅通过调用其
Error()
方法将
error
转换为
string
意味着我们没有遵循自定义编组逻辑。
因此,我建议创建我们自己的错误切片类型,在其上我们可以实现我们的编组逻辑,应该是:
- 检查错误值是否实现了
json.Marshaler
,如果是,则让它自行编组
- 否则,作为后备情况,调用
error.Error()
以“获得”可以轻松编组的string
下面是示例代码:
type JSONErrs []error
func (je JSONErrs) MarshalJSON() ([]byte, error) {
res := make([]interface{}, len(je))
for i, e := range je {
if _, ok := e.(json.Marshaler); ok {
res[i] = e
} else {
res[i] = e.Error()
}
}
return json.Marshal(res)
}
以下是如何使用它的方法:
err := person.Validate()
c.JSON(422, gin.H{"errors" : JSONErrs(err)})
让我们测试一下JSONErrs
。同时,我们还将使用一个实现了自定义编组逻辑的自定义错误类型:
type MyErr struct{ line int }
func (me MyErr) Error() string { return "Invalid input!" }
func (me MyErr) MarshalJSON() ([]byte, error) {
return json.Marshal(
struct {
Type, Error string
AtLine int
}{"MyErr", me.Error(), me.line})
}
以下是测试代码:
errs := []error{
errors.New("first"),
errors.New("second"),
MyErr{16},
}
data, err := json.Marshal(JSONErrs(errs))
fmt.Println(string(data), err)
输出结果(在Go Playground上尝试):
["first","second",{"Type":"MyErr","Error":"Invalid input!","AtLine":16}] <nil>