繁体   English   中英

在 Go 中将平面 JSON 解组为嵌套结构

[英]Unmarshall flat JSON into a nested struct in Go

我想从包含另一个结构的平面 JSON 创建一个嵌套结构:

type Todo struct {
    Todo_id   int    `json:"todo_id" db:"todo_id"`
    Todo_name string `json:"todo_name" db:"todo_name"`

    User_id int         `json:"user_id" db:"user_id"`
    Subs    []Sub       `json:"subs" db:"subs"`
    Times   Parsed_Time `json:"times" db:"times"`
}

当我解组 JSON 时,我收到“缺少目标名称截止日期”错误,因为截止日期位于 Parsed_Time 结构内。 有没有办法自定义解组 JSON,以便在没有错误的情况下省略部分 JSON? 我想单独创建一个带有空 Times 的 Todo 结构,然后再次运行 Unmarshal 以将截止日期和其余时间戳分别提取到另一个结构中。 这是为了避免向数据库发出两个单独的 Get 请求。

是的 - 你可能已经知道如果一个类型实现了json.Unmarshaler ,它将在json.Unmarshal()被调用时使用该类型作为第二个参数。 经常发生的问题是需要将接收器的类型解组为自定义解组代码的一部分。 这可以通过多种方式克服,其中最常见的是使用本地类型进行解组。 不过,您可以通过明智地使用类型别名来节省大量重复代码。

我已经更新了您上面的代码,以存根Todo的字段表示的类型,如下所示:

type Sub int

type ParsedTime struct {
    Deadline time.Time
    Created  time.Time
}

type Todo struct {
    ID   int          `json:"todo_id" db:"todo_id"`
    Name string       `json:"todo_name" db:"todo_name"`
    UserID int        `json:"user_id" db:"user_id"`
    Subs   []Sub      `json:"subs" db:"subs"`
    Times  ParsedTime `json:"-" db:"times"`
}

请注意,相关性的唯一变化是在调用 `json.Unmarshal 时忽略Times字段。 我只更改了字段名称以让我的 IDE 的 linter 闭嘴! 使用这些类型,我们可以定义一个自定义解组器,如下所示:

func (t *Todo) UnmarshalJSON(data []byte) error {
    type TodoJSON Todo

    todo := struct {
        *TodoJSON
        Deadline string `json:"deadline"`
    }{
        TodoJSON: (*TodoJSON)(t),
    }

    if err := json.Unmarshal(data, &todo); err != nil {
        return err
    }

    deadline, err := time.Parse(time.RFC3339, todo.Deadline)
    if err != nil {
        return err
    }

    t.Times.Deadline = deadline

    return nil
}

此代码中使用了两种关键技术。 首先,使用类型别名消除了直接使用Todo时会发生的无限递归。 其次,创建嵌入*Todo的本地类型消除了完全重新键入Todo类型字段的需要 - 只需要添加所需的Deadline字段。 我还假设Deadlinetime.Time以表明此代码还允许在分配字段之前对其进行处理( time.Parse() )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM