normalizeStruct 处理结构体 注意:Go 的 json.Marshal 对结构体已经是确定性的(按字段定义顺序) 但我们仍需递归处理嵌套的 map
(v reflect.Value)
| 177 | // 注意:Go 的 json.Marshal 对结构体已经是确定性的(按字段定义顺序) |
| 178 | // 但我们仍需递归处理嵌套的 map |
| 179 | func normalizeStruct(v reflect.Value) any { |
| 180 | t := v.Type() |
| 181 | result := make(orderedMap, 0) |
| 182 | |
| 183 | for i := 0; i < v.NumField(); i++ { |
| 184 | field := t.Field(i) |
| 185 | fieldVal := v.Field(i) |
| 186 | |
| 187 | // 跳过未导出字段 |
| 188 | if field.PkgPath != "" { |
| 189 | continue |
| 190 | } |
| 191 | |
| 192 | // 获取 JSON tag |
| 193 | jsonTag := field.Tag.Get("json") |
| 194 | if jsonTag == "-" { |
| 195 | continue |
| 196 | } |
| 197 | |
| 198 | // 解析 tag |
| 199 | name := field.Name |
| 200 | omitempty := false |
| 201 | if jsonTag != "" { |
| 202 | parts := splitTag(jsonTag) |
| 203 | if parts[0] != "" { |
| 204 | name = parts[0] |
| 205 | } |
| 206 | for _, opt := range parts[1:] { |
| 207 | if opt == "omitempty" { |
| 208 | omitempty = true |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | // 处理 omitempty |
| 214 | if omitempty && isEmptyValue(fieldVal) { |
| 215 | continue |
| 216 | } |
| 217 | |
| 218 | result = append(result, orderedMapEntry{ |
| 219 | Key: name, |
| 220 | Value: normalizeValue(fieldVal), |
| 221 | }) |
| 222 | } |
| 223 | |
| 224 | return result |
| 225 | } |
| 226 | |
| 227 | // splitTag 分割 JSON tag |
| 228 | func splitTag(tag string) []string { |
no test coverage detected