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

golang json.Marshal 什么情况下会报错?,第1张

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。

参考 https://golang.org/pkg/encoding/json/#Marshalhttps://stackoverflow.com/questions/33903552/what-input-will-cause-golangs-json-marshal-to-return-an-error

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/995923.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存