Closed draveness closed 2 years ago
对map中的int类型元素进行Marshal后,再进行 Unmarshal ,原来int类型就变成 float64 了。“通过 newTypeEncoder 选择到 intEncoder 进行Marshal” 这一步应该没错,是 Unmarshal 的时候出的问题吗?
func main() {
u1 := map[string]interface{}{
"Name": "tom",
"Age": 18,
}
for k, v := range u1 {
fmt.Printf("key:%v value:%v type of value:%T\n", k, v, v) //此处age是int
}
b, _ := json.Marshal(u1)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
fmt.Printf("key:%v value:%v type of value:%T\n", k, v, v) //此处的age是float64
}
}
对map中的int类型元素进行Marshal后,再进行 Unmarshal ,原来int类型就变成 float64 了。“通过 newTypeEncoder 选择到 intEncoder 进行Marshal” 这一步应该没错,是 Unmarshal 的时候出的问题吗?
func main() { u1 := map[string]interface{}{ "Name": "tom", "Age": 18, } for k, v := range u1 { fmt.Printf("key:%v value:%v type of value:%T\n", k, v, v) //此处age是int } b, _ := json.Marshal(u1) var m map[string]interface{} _ = json.Unmarshal(b, &m) for k, v := range m { fmt.Printf("key:%v value:%v type of value:%T\n", k, v, v) //此处的age是float64 } }
JSON 的标准里其实只有 number 类型,float64 是 Go 做的统一转换,如果想转回 int 类型需要用 struct 给标准库一个提示用于反序列化。
@draveness
对map中的int类型元素进行Marshal后,再进行 Unmarshal ,原来int类型就变成 float64 了。“通过 newTypeEncoder 选择到 intEncoder 进行Marshal” 这一步应该没错,是 Unmarshal 的时候出的问题吗?
func main() { u1 := map[string]interface{}{ "Name": "tom", "Age": 18, } for k, v := range u1 { fmt.Printf("key:%v value:%v type of value:%T\n", k, v, v) //此处age是int } b, _ := json.Marshal(u1) var m map[string]interface{} _ = json.Unmarshal(b, &m) for k, v := range m { fmt.Printf("key:%v value:%v type of value:%T\n", k, v, v) //此处的age是float64 } }
JSON 的标准里其实只有 number 类型,float64 是 Go 做的统一转换,如果想转回 int 类型需要用 struct 给标准库一个提示用于反序列化。
嗦嘎,int的编码器就将int变成number了是吧,也就是JavaScript 中的双精度浮点型格式,然后写入缓冲区
感觉 encodeState 和 decodeState 这个结构体非常重要的呀,序列化反序列的移位操作都被它的方法封装了,过程就不需要关心这些操作了。
纠错:在不追求机制性能的情况下 =》 在不追求极致性能的情况下
2020-06-02 UPDATES: 已修复
看到stringEncoder,有一事不明,请教。 调用Marshal(v.String()),那不是又会回到这里?怎么退出的呢?
func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) {
if v.Type() == numberType {
numStr := v.String()
// In Go1.5 the empty string encodes to "0", while this is not a valid number literal
// we keep compatibility so check validity after this.
if numStr == "" {
numStr = "0" // Number's zero-val
}
if !isValidNumber(numStr) {
e.error(fmt.Errorf("json: invalid number literal %q", numStr))
}
e.WriteString(numStr)
return
}
if opts.quoted {
sb, err := Marshal(v.String()) <--- 这个地方是递归?那怎么退出呢?
if err != nil {
e.error(err)
}
e.string(string(sb), opts.escapeHTML)
} else {
e.string(v.String(), opts.escapeHTML)
}
}
@yanping-li 看到stringEncoder,有一事不明,请教。 调用Marshal(v.String()),那不是又会回到这里?怎么退出的呢?
func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { if v.Type() == numberType { numStr := v.String() // In Go1.5 the empty string encodes to "0", while this is not a valid number literal // we keep compatibility so check validity after this. if numStr == "" { numStr = "0" // Number's zero-val } if !isValidNumber(numStr) { e.error(fmt.Errorf("json: invalid number literal %q", numStr)) } e.WriteString(numStr) return } if opts.quoted { sb, err := Marshal(v.String()) <--- 这个地方是递归?那怎么退出呢? if err != nil { e.error(err) } e.string(string(sb), opts.escapeHTML) } else { e.string(v.String(), opts.escapeHTML) } }
如果是递归,新的 string 在 Marshal 时的 option 只要 quoted = false
这里就一定会中止,看一下进入分支的条件
请问一下 在marshal的时候在哪判断的私有变量呢? 通过反射应该是可以拿到私有变量的,但是在marshal的时候私有变量是不可导出的
@jzhahaha 请问一下 在marshal的时候在哪判断的私有变量呢? 通过反射应该是可以拿到私有变量的,但是在marshal的时候私有变量是不可导出的
从 typeFields 方法里看看
var ( wg sync.WaitGroup f encoderFunc ) wg.Add(1) fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(e *encodeState, v reflect.Value, opts encOpts) { wg.Wait() f(e, v, opts) }))
大佬,抱歉,有个问题想问下,这个地方为啥要用waitgroup呢?
https://draveness.me/golang-json
Go 语言 JSON 的实现原理