我在Golang中使用mapstruct.Decode函数将映射转换为嵌套结构,但它无法正常工作,并且一些值在解码的结构中丢失。以下是一个最小案例,其中包含我的代码的一部分(游乐场:https://go.dev/play/p/scS7gWyETGy):
// Events represent repository events
type Events []Event
// Event represent a repository event
type Event struct {
ID string `json:"id"`
Type string `json:"type"`
Payload struct {
PushID int `json:"push_id"`
Action string `json:"action"`
Size int `json:"size"`
PullRequest PullRequest `json:"pull_request"`
} `json:"payload"`
}
// PullRequest represents pull request from github api
type PullRequest struct {
URL string `json:"url"`
State string `json:"state"`
}
func main() {
strg := "[{\"created_at\": \"2024-01-19T05:32:35Z\", \"id\": \"34950536433\", \"payload\": {\"action\": \"reopened\", \"pull_request\": {\"additions\": 1, \"number\": 23, \"state\": \"open\", \"url\": \"test.com\"}}, \"public\": true, \"type\": \"PullRequestEvent\"}]"
evts := []interface{}{}
events := Events{}
json.Unmarshal([]byte(strg), &evts)
mapstructure.Decode(evts, &events)
fmt.Printf("%+v\n", events[0])
fmt.Printf("%+v\n", events[0].Payload.PullRequest)
}
正如预期的那样,输出应该是这样的:
{ID:34950536433 Type:PullRequestEvent Payload:{PushID:0 Action:reopened Size:0 PullRequest:{URL:test.com State:open}}}
{URL: test.com State:open}
但实际上我得到了以下结果:
{ID:34950536433 Type:PullRequestEvent Payload:{PushID:0 Action:reopened Size:0 PullRequest:{URL: State:}}}
{URL: State:}
我认为这是一个非常简单的案例,应该不会有任何问题,但事实并非如此。谁能帮我找出问题所在吗?
我想知道这个库是否有错误
mapstructure
或者我在使用它时犯了一些错误。
Mapstruct 不会解析名称中带有“_”(下划线)的字段。您需要指示它正确执行此操作:
PullRequest PullRequest `json:"pull_request" mapstructure:"pull_request"`
mapstruct 库期望输入映射具有与目标 Go 结构紧密匹配的结构。如果输入映射中的嵌套结构与 Go 中的嵌套结构不完全匹配,则库可能无法正确解码它。
在您的情况下,Event 结构中的 PullRequest 结构没有被填充,因为 JSON 中的键不直接对应于映射结构所需的嵌套结构格式。 MapStructure 库正在寻找每个字段的直接匹配,但没有找到嵌套 PullRequest 结构的匹配。
以下是解决此问题的几种方法:
扁平化结构:
修改 Go 结构以反映 JSON 的平面结构。这意味着删除嵌套结构并将所有字段直接放置在事件结构中。这可能有点混乱,但却是一种简单的方法。
直接使用JSON Unmarshal:
由于您的输入是 JSON,请考虑直接在事件切片中使用
json.Unmarshal
,而不是首先解组为 []interface{}
,然后使用映射结构。这种方法更简单,并且利用标准库的 JSON 解码,可以很好地处理嵌套结构。
以下是直接使用
json.Unmarshal
的方法:
func main() {
strg := "[{\"created_at\": \"2024-01-19T05:32:35Z\", \"id\": \"34950536433\", \"payload\": {\"action\": \"reopened\", \"pull_request\": {\"additions\": 1, \"number\": 23, \"state\": \"open\", \"url\": \"test.com\"}}, \"public\": true, \"type\": \"PullRequestEvent\"}]"
events := Events{}
json.Unmarshal([]byte(strg), &events)
fmt.Printf("%+v\n", events[0])
fmt.Printf("%+v\n", events[0].Payload.PullRequest)
}