golang json.Marshal 什么情况下会报错?

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。

UnsupportedTypeError

// 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

UnsupportedValueError

// 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错误的情况有:

  • 浮点数值为无穷大,无穷小或者NaN
_, err := json.Marshal(math.Inf(1))
_, ok := err.(*json.UnsupportedValueError) // ok == true
  • map、slice和pointer出现循环引用
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 不支持的标准类型有 Complex64Complex128ChanFuncUnsafePointer ,这种情况下会返回 UnsupportedTypeError 。对于不支持的数据类型,需要实现 MarshalJSON 或者 encoding.TextMarshaler 接口。对于不支持的值,会返回 UnsupportedValueError 错误,如浮点数的无穷大,无穷小,NaN 和出现循环引用的 map、slice和pointer。

参考

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值