Golang MapStructure.Decode 不解析所有字段

问题描述 投票:0回答:2

我在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
或者我在使用它时犯了一些错误。

json go decode
2个回答
0
投票

Mapstruct 不会解析名称中带有“_”(下划线)的字段。您需要指示它正确执行此操作:

PullRequest PullRequest `json:"pull_request" mapstructure:"pull_request"`

0
投票

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)
}
© www.soinside.com 2019 - 2024. All rights reserved.