[英]Unmarshall flat JSON into a nested struct in Go
There is a nested struct that I want to create from a flat JSON that includes another struct:我想从包含另一个结构的平面 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"`
}
When I unmarshal a JSON I receive a "missing destination name deadline" error because Deadline is inside a Parsed_Time struct.当我解组 JSON 时,我收到“缺少目标名称截止日期”错误,因为截止日期位于 Parsed_Time 结构内。 Is there a way to custom unmarshal JSON so that parts of the JSON would be omitted without error?
有没有办法自定义解组 JSON,以便在没有错误的情况下省略部分 JSON? I would like to separately create a Todo struct with an empty Times, then run Unmarshal again to extract deadline and the rest of timestamps separately into another struct.
我想单独创建一个带有空 Times 的 Todo 结构,然后再次运行 Unmarshal 以将截止日期和其余时间戳分别提取到另一个结构中。 This is to avoid making two separate Get requests to a database.
这是为了避免向数据库发出两个单独的 Get 请求。
Yes - you probably already know that if a type implements json.Unmarshaler
, it will be used when json.Unmarshal()
is called with that type as the second parameter.是的 - 你可能已经知道如果一个类型实现了
json.Unmarshaler
,它将在json.Unmarshal()
被调用时使用该类型作为第二个参数。 The problem that often occurs is the need to unmarshal the receiver's type as part of the custom unmarshal code.经常发生的问题是需要将接收器的类型解组为自定义解组代码的一部分。 This can be overcome in several ways, the most common of which is to use a local type to do the unmarshaling.
这可以通过多种方式克服,其中最常见的是使用本地类型进行解组。 You can save a lot of duplicate code with the judicious use of a type alias though.
不过,您可以通过明智地使用类型别名来节省大量重复代码。
I've updated your code above to stub out the types represented by Todo
's fields as follows:我已经更新了您上面的代码,以存根
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"`
}
Note that the only change of relevance is to ignore the Times
field when `json.Unmarshal is called.请注意,相关性的唯一变化是在调用 `json.Unmarshal 时忽略
Times
字段。 I only changed the field names to get my IDE's linter to shut up!我只更改了字段名称以让我的 IDE 的 linter 闭嘴! With these types, we can define a custom unmarshaler as follows:
使用这些类型,我们可以定义一个自定义解组器,如下所示:
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
}
There are two key techniques used in this code.此代码中使用了两种关键技术。 First, using a type alias eliminates the infinite recursion that would occur if
Todo
was used directly.首先,使用类型别名消除了直接使用
Todo
时会发生的无限递归。 Second, creating a local type that embeds *Todo
eliminates the need to completely retype the Todo
type's fields - only the desired Deadline
field needs to be added.其次,创建嵌入
*Todo
的本地类型消除了完全重新键入Todo
类型字段的需要 - 只需要添加所需的Deadline
字段。 I also assumed that Deadline
was a time.Time
to show that this code also allows the field to be processed before it's assigned ( time.Parse()
).我还假设
Deadline
是time.Time
以表明此代码还允许在分配字段之前对其进行处理( time.Parse()
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.