From fa33b05e7c560c80fca0fb03c1d16377091ed728 Mon Sep 17 00:00:00 2001 From: "chen.yang" Date: Tue, 3 Aug 2021 09:25:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20Golang=20Map=20=E8=BD=AC?= =?UTF-8?q?=20Json=20=E7=9A=84=E9=A1=BA=E5=BA=8F=E9=97=AE=E9=A2=98.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: chen.yang --- .../Go/Basic/Golang_Map_转_Json_的顺序问题.md | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Software/Development/Language/Go/Basic/Golang_Map_转_Json_的顺序问题.md diff --git a/Software/Development/Language/Go/Basic/Golang_Map_转_Json_的顺序问题.md b/Software/Development/Language/Go/Basic/Golang_Map_转_Json_的顺序问题.md new file mode 100644 index 0000000..c70663e --- /dev/null +++ b/Software/Development/Language/Go/Basic/Golang_Map_转_Json_的顺序问题.md @@ -0,0 +1,61 @@ +# [Golang Map 转 Json 的顺序问题](https://blog.csdn.net/xz_studying/article/details/103219478) + +我们都知道 map 是无序的,每次取出 key/value 的顺序都可能不一致,但 map 转 json 的顺序是不是也是无序的吗?尽管 json 中的参数顺序大部分情况下对使用没有影响,我们不妨看看源码中怎么处理的。 + +## 1.结论 + +* map 转 json 是有序的,按照字符编码升序排列 key。 + +## 2.溯源 + +源码位于encoding/json/encode.go中: + +```go +type mapEncoder struct { + elemEnc encoderFunc +} + +func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { + if v.IsNil() {//为nil时,返回null + e.WriteString("null") + return + } + e.WriteByte('{') + + // Extract and sort the keys. + keys := v.MapKeys()//获取map中的所有keys + sv := make([]reflectWithString, len(keys)) + for i, v := range keys { + sv[i].v = v + if err := sv[i].resolve(); err != nil {//处理key,尤其是非string(int/uint)类型的key转string + e.error(&MarshalerError{v.Type(), err}) + } + } + //排序,升序,直接比较字符串 + sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s }) + + for i, kv := range sv { + if i > 0 { + e.WriteByte(',') + } + e.string(kv.s, opts.escapeHTML) + e.WriteByte(':') + me.elemEnc(e, v.MapIndex(kv.v), opts) + } + e.WriteByte('}') +} + +func newMapEncoder(t reflect.Type) encoderFunc { + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !t.Key().Implements(textMarshalerType) { + return unsupportedTypeEncoder + } + } + me := mapEncoder{typeEncoder(t.Elem())} + return me.encode +} +```