func Marshal(v interface{}) ([]byte, error)
我们一般会这样使用 b, err := json.Marshal(data) ,也就是应该检查Marshal返回的错误,但很少遇到这个函数报错,那么什么情况下json.Marshal会返回错误。通过官方文档,找到了以下的说明:
Channel, complex, and function values cannot be encoded in JSON. Attempting to encode such a value causes Marshal to return an UnsupportedTypeError.
JSON cannot represent cyclic data structures and Marshal does not handle them. Passing cyclic structures to Marshal will result in an error.
Channel, complex, function 等类型不能被json序列化,Marshal会返回UnsupportedTypeError错误。循环引用的数据结构也会引起Marshal报错。对于不支持的类型Marshal报错UnsupportedTypeError,对于支持的类型,但不支持的值会报错UnsupportedValueError。
// newTypeEncoder constructs an encoderFunc for a type.
// The returned encoder only checks CanAddr when allowAddr is true.
func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
// If we have a non-pointer value whose type implements
// Marshaler with a value receiver, then we're better off taking
// the address of the value - otherwise we end up with an
// allocation as we cast the value to an interface.
if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(marshalerType) {
return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false))
}
if t.Implements(marshalerType) {
return marshalerEncoder
}
if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(textMarshalerType) {
return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false))
}
if t.Implements(textMarshalerType) {
return textMarshalerEncoder
}
switch t.Kind() {
case reflect.Bool:
return boolEncoder
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return intEncoder
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return uintEncoder
case reflect.Float32:
return float32Encoder
case reflect.Float64:
return float64Encoder
case reflect.String:
return stringEncoder
case reflect.Interface:
return interfaceEncoder
case reflect.Struct:
return newStructEncoder(t)
case reflect.Map:
return newMapEncoder(t)
case reflect.Slice:
return newSliceEncoder(t)
case reflect.Array:
return newArrayEncoder(t)
case reflect.Ptr:
return newPtrEncoder(t)
default:
return unsupportedTypeEncoder
}
}
如果值实现了json.Marshaler接口, Mashal会调用MarshalJSON方法生成JSON。如果MarshalJSON不存在,但值实现了encoding.TextMarshaler接口,那么Marshal会调用MarshalText方法生成JSON字符串。从源码t.Kind()的这个switch结构可知,Marshal不支持以下标准类型的JSON序列化,会返回UnsupportedTypeError错误。
Complex64,Complex128,Chan,Func,UnsafePointer
json.Marshal(complex64(1)) // Complex64
json.Marshal(complex128(1)) // Complex128
json.Marshal(make(chan struct{})) // Chan
json.Marshal(func() {}) // Func
json.Marshal(unsafe.Pointer(nil)) // UnsafePointer
// An UnsupportedValueError is returned by Marshal when attempting
// to encode an unsupported value.
type UnsupportedValueError struct {
Value reflect.Value
Str string
}
func (e *UnsupportedValueError) Error() string {
return "json: unsupported value: " + e.Str
}
func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
f := v.Float()
if math.IsInf(f, 0) || math.IsNaN(f) {
e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))})
}
// ...
}
func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
// ...
if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter {
// We're a large number of nested ptrEncoder.encode calls deep;
// start checking if we've run into a pointer cycle.
ptr := v.Pointer()
if _, ok := e.ptrSeen[ptr]; ok {
e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())})
}
e.ptrSeen[ptr] = struct{}{}
defer delete(e.ptrSeen, ptr)
}
//...
}
func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
// ...
if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter {
// We're a large number of nested ptrEncoder.encode calls deep;
// start checking if we've run into a pointer cycle.
// Here we use a struct to memorize the pointer to the first element of the slice
// and its length.
ptr := struct {
ptr uintptr
len int
}{v.Pointer(), v.Len()}
if _, ok := e.ptrSeen[ptr]; ok {
e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())})
}
e.ptrSeen[ptr] = struct{}{}
defer delete(e.ptrSeen, ptr)
}
// ...
}
func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
// ...
if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter {
// We're a large number of nested ptrEncoder.encode calls deep;
// start checking if we've run into a pointer cycle.
ptr := v.Interface()
if _, ok := e.ptrSeen[ptr]; ok {
e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())})
}
e.ptrSeen[ptr] = struct{}{}
defer delete(e.ptrSeen, ptr)
}
// ...
}
分析以上源码可以看出,出现UnsupportedValueError错误的情况有:
_, err := json.Marshal(math.Inf(1))
_, ok := err.(*json.UnsupportedValueError) // ok == true
package main
import (
"encoding/json"
"fmt"
)
type Node struct {
Data string
Next *Node
}
func main() {
node := &Node{
Data: "John",
}
node.Next = node
_, err := json.Marshal(node)
_, ok := err.(*json.UnsupportedValueError)
fmt.Println("UnsupportedValueError ", ok)
}
Marshal 不支持的标准类型有 Complex64 ,Complex128 ,Chan ,Func ,UnsafePointer ,这种情况下会返回 UnsupportedTypeError 。对于不支持的数据类型,需要实现 MarshalJSON 或者 encoding.TextMarshaler 接口。对于不支持的值,会返回 UnsupportedValueError 错误,如浮点数的无穷大,无穷小,NaN 和出现循环引用的 map、slice和pointer。