你有没有遇到过json编码error为空的情况?我们一起看一下。
首先我们知道error是一个interface,需要实现一个Error()方法返回错误描述字符串。
打印error
下面的情况可以正常输出error的错误描述:
1 2 3 4 5 6 7 8 9 10 11 12 |
package main import ( "errors" "fmt" ) func main() { // Println内部应该会反射error接口, 调用err.Error()得到描述字符串 err := errors.New("出错啦!") fmt.Println(err) } |
输出:
出错啦!
如果我们追到Println源码的深处,大概可以看到这样一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 |
switch verb { case 'v', 's', 'x', 'X', 'q': // Is it an error or Stringer? // The duplication in the bodies is necessary: // setting handled and deferring catchPanic // must happen before calling the method. switch v := p.arg.(type) { case error: handled = true defer p.catchPanic(p.arg, verb, "Error") p.fmtString(v.Error(), verb) return |
可见,实际上最底层也是反射判定了它是一个实现了error接口的对象,然后调用了它的Error()方法。
json编码error
我们当然会想当然的认为json编码的时候也会自动取Error()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package main import ( "encoding/json" "errors" "fmt" ) func main() { err := errors.New("出错啦!") // 然而json则不会 d := map[string]interface{}{ "error_msg": err, } j, _ := json.Marshal(d) fmt.Println(string(j)) } |
然而实际输出的是:
1 |
{"error_msg":{}} |
err竟然被编码成一个{},怎么解释呢?
- 首先可以明确,json库肯定没有反射特殊判断过error interface类型。
- 其次,为什么是一个空map呢?其实空map对应的就是一个空struct。
如果我们去看errors.New返回的是一个什么对象,就会明白为什么会是一个空map:
1 2 3 4 5 6 7 8 |
// errorString is a trivial implementation of error. type errorString struct { s string } func (e *errorString) Error() string { return e.s } |
因为errors.New返回的就是一个errorString对象,然而这样一个普通的struct内部唯一的字段s又是小写的(未导出),所以json编码的时候只能将其编码为{},仅此而已。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~
