什么输入会导致golang的json.Marshal返回错误?

文档

JSON 不能表示循环数据结构,Marshal 不处理它们。将循环结构传递给 Marshal 将导致无限递归。

我遇到过这种情况,这会导致运行时恐慌。

我想知道是否有人可以提供一个工作程序来演示 json.Marshal 返回非零错误的非恐慌情况。最好的答案显然包括使用的输入


有只小跳蛙
浏览 181回答 4
4回答

芜湖不芜

只是为了补充乔纳森的回答, json.Marshal 函数可以返回两种类型的错误:UnsupportedTypeError或UnsupportedValueError第一个可能是由 Jonathan 所说的,通过尝试对无效类型进行编组:_, err := json.Marshal(make(chan int))_, ok := err.(*json.UnsupportedTypeError) // ok == true另一方面,您还可以通过传递无效值让 Marshal 函数返回错误:_, err := json.Marshal(math.Inf(1))_, ok := err.(*json.UnsupportedValueError) // ok == true

尚方宝剑之说

更新:现在使用通道而不是 map[int]int 来引发错误特定于 Go 的结构,例如func或chan拒绝序列化:package mainimport (    "encoding/json"    "fmt")func main() {    value := make(chan int)    _, err := json.Marshal(value)    fmt.Println(err)}

慕码人8056858

阅读源代码可以找到这样一个判断编码器的函数,如果不存在会返回编组错误:https : //github.com/golang/go/blob/master/src/encoding/json/encode.gofunc newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {    // ignored    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    }}我们可以在https://github.com/golang/go/blob/master/src/reflect/type.go找到各种枚举所以不难看出,不在上述函数中的种类是无法编组的:UnsafePointer,Complex64,Complex128,Chan,Func例子:        json.Marshal(unsafe.Pointer(nil)) // UnsafePointer        json.Marshal(complex64(1))        // Complex64        json.Marshal(complex128(1))       // Complex128        json.Marshal(make(chan struct{})) // Chan        json.Marshal(func() {})           // Func

临摹微笑

前段时间我正在解决一个在golang中序列化/反序列化循环引用的问题,所有链接都指向这个问题。然而,这有点误导,因为问题更广泛。如果你遇到了和我一样的情况,并且找不到如何处理循环引用的解决方案,你现在可以使用tahwil——我在 github 上发布的一个新库。据我所知,它现在是唯一一个以通用方式促进循环数据结构的序列化/反序列化的库。自述文件提供了有关如何使用该库的信息,因此我将在此处仅复制示例。编码:package mainimport (    "encoding/json"    "fmt"    "github.com/go-extras/tahwil")type Person struct {    Name     string    Parent   *Person    Children []*Person}func main() {    parent := &Person{        Name: "Arthur",        Children: []*Person{            {                Name: "Ford",            },            {                Name: "Trillian",            },        },    }    parent.Children[0].Parent = parent    parent.Children[1].Parent = parent    v, err := tahwil.ToValue(parent)    if err != nil {        panic(err)    }    res, err := json.Marshal(v)    if err != nil {        panic(err)    }    fmt.Println(string(res))}解码:package mainimport (    "encoding/json"    "fmt"    "github.com/go-extras/tahwil")type Person struct {    Name     string    `json:"name"`    Parent   *Person   `json:"parent"`    Children []*Person `json:"children"`}func prepareData() []byte {    parent := &Person{        Name: "Arthur",        Children: []*Person{            {                Name: "Ford",            },            {                Name: "Trillian",            },        },    }    parent.Children[0].Parent = parent    parent.Children[1].Parent = parent    v, err := tahwil.ToValue(parent)    if err != nil {        panic(err)    }    res, err := json.Marshal(v)    if err != nil {        panic(err)    }    return res}func main() {    data := &tahwil.Value{}    res := prepareData()    err := json.Unmarshal(res, data)    if err != nil {        panic(err)    }    person := &Person{}    err = tahwil.FromValue(data, person)    if err != nil {        panic(err)    }    fmt.Printf(`Name: %sChildren:    - %s    -- parent name: %s    - %s    -- parent name: %s`, person.Name,        person.Children[0].Name,        person.Children[0].Parent.Name,        person.Children[1].Name,        person.Children[1].Parent.Name)}主要思想是将原始数据转换为tahwil.Value{},这实际上将refid'添加到您的所有字段中。每当tahwil遇到循环引用时,它都会用引用替换实际对象。之后,该图在技术上不再是循环的,因此可以编组为 json。恢复数据意味着反向操作,即任何引用都将被指向对象的指针替换。PS 为什么tahwil?我试图为这个名字找到一些不常见的词,并找到了一个阿拉伯语词(تحويل),意思是转换。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go