Go语言如何将二维数组解析为自定义结构体并跳过指定字段
实现方案
你从API拿到的是位置固定的二维数组格式JSON,不是带键名的对象结构,无法直接通过结构体tag做默认映射,通过自定义结构体的UnmarshalJSON方法按索引取值、直接跳过目标字段即可实现需求,同时可以顺带处理时间戳格式转换。
字段位置对应关系
先明确单条数据的索引和字段映射,索引5为需要跳过的字段:
- 索引0:毫秒级注册时间戳 →
RegistrationDate - 索引1:姓名 →
Name - 索引2:地址 →
Address - 索引3:城市 →
City - 索引4:州/省 →
State - 索引5:值为
"pass this"的无用字段,直接跳过 - 索引6:邮编 →
Zip - 索引7:毫秒级过期时间戳 →
ExpirationDate
完整实现代码
package main import ( "encoding/json" "fmt" "time" ) type Address struct { RegistrationDate string `json:"registrationDate"` Name string `json:"name"` Address string `json:"address"` City string `json:"city"` State string `json:"state"` Zip string `json:"zip"` ExpirationDate string `json:"expirationDate"` } // UnmarshalJSON 自定义Address的反序列化逻辑 func (a *Address) UnmarshalJSON(data []byte) error { // 先将单条数据解析为通用切片,元素顺序和API返回完全一致 var arr []interface{} if err := json.Unmarshal(data, &arr); err != nil { return err } // 校验数组长度避免越界 if len(arr) != 8 { return fmt.Errorf("invalid data length, expected 8 elements, got %d", len(arr)) } // 按索引赋值,跳过索引5的无用字段 // 处理注册时间戳:JSON数字默认解析为float64,转毫秒时间后格式化 regTs, ok := arr[0].(float64) if !ok { return fmt.Errorf("invalid type for registration timestamp") } a.RegistrationDate = time.UnixMilli(int64(regTs)).Format("2006-01-02") // 可替换为你需要的时间格式 // 赋值字符串字段 if a.Name, ok = arr[1].(string); !ok { return fmt.Errorf("invalid type for name") } if a.Address, ok = arr[2].(string); !ok { return fmt.Errorf("invalid type for address") } if a.City, ok = arr[3].(string); !ok { return fmt.Errorf("invalid type for city") } if a.State, ok = arr[4].(string); !ok { return fmt.Errorf("invalid type for state") } // 索引5字段直接跳过,不做任何处理 if a.Zip, ok = arr[6].(string); !ok { return fmt.Errorf("invalid type for zip") } // 处理过期时间戳 expTs, ok := arr[7].(float64) if !ok { return fmt.Errorf("invalid type for expiration timestamp") } a.ExpirationDate = time.UnixMilli(int64(expTs)).Format("2006-01-02") // 可替换为你需要的时间格式 return nil } func main() { // 模拟API返回的原始数据 raw := `[ [1501545600000,"a","b","c","d","pass this","e",1651363200000], [1504224000000,"a","b","c","d","pass this","e",1654041600000] ]` var res []Address if err := json.Unmarshal([]byte(raw), &res); err != nil { panic(err) } // 打印解析结果,不会包含跳过的字段 for _, addr := range res { fmt.Printf("%+v\n", addr) } }
补充说明
- 如果你不需要把时间戳转为日期格式,只需要存数字字符串,可以把时间处理部分替换为
strconv.FormatInt(int64(regTs), 10)即可,无需引入time包。 - 这种实现完全不依赖索引5的具体值,只要API返回的数组元素位置不变,哪怕该字段后续值发生变化,也不会影响解析结果。
- 如果对解析性能有要求,可以把
[]interface{}替换为[]json.RawMessage,按索引单独反序列化对应字段,减少类型断言的开销。
内容的提问来源于stack exchange,提问作者user15811966
相关产品推荐
相关产品推荐

