4 回答
TA贡献1796条经验 获得超7个赞
只是为了补充乔纳森的回答, 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
TA贡献1788条经验 获得超4个赞
更新:现在使用通道而不是 map[int]int 来引发错误
特定于 Go 的结构,例如func或chan拒绝序列化:
package main
import (
"encoding/json"
"fmt"
)
func main() {
value := make(chan int)
_, err := json.Marshal(value)
fmt.Println(err)
}
TA贡献1803条经验 获得超6个赞
阅读源代码可以找到这样一个判断编码器的函数,如果不存在会返回编组错误:https : //github.com/golang/go/blob/master/src/encoding/json/encode.go
func 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
TA贡献1982条经验 获得超2个赞
前段时间我正在解决一个在golang中序列化/反序列化循环引用的问题,所有链接都指向这个问题。然而,这有点误导,因为问题更广泛。
如果你遇到了和我一样的情况,并且找不到如何处理循环引用的解决方案,你现在可以使用tahwil——我在 github 上发布的一个新库。据我所知,它现在是唯一一个以通用方式促进循环数据结构的序列化/反序列化的库。
自述文件提供了有关如何使用该库的信息,因此我将在此处仅复制示例。
编码:
package main
import (
"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 main
import (
"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: %s
Children:
- %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?我试图为这个名字找到一些不常见的词,并找到了一个阿拉伯语词(تحويل),意思是转换。
- 4 回答
- 0 关注
- 180 浏览
添加回答
举报