英文:
Separate struct from its json logic in golang?
问题
在Go语言中,有一种惯用的方法可以将结构体与其JSON编组逻辑分离吗?
通常情况下:
package models
type Foo struct {
Name `json:"full_name"`
}
但是我想要关注点分离。我不希望在models
包中的结构体中指定json
逻辑,也许可以将json
逻辑放在另一个serializers
包中。你会如何在Go语言中实现这一点?也许可以类似于rails
项目中处理active_model_serializers
代码的方式。
英文:
Is there an idiomatic way in go to separate a struct from its json marshal logic?
Normally:
package models
type Foo struct {
Name `json:"full_name"`
}
But I want a separation of concerns. I don't want the json
specifying logic in the models
package with the struct, maybe put the json
logic in another serializers
package. How would you do that in idiomatic go? Maybe similar to how rails
projects handle active_model_serializers
code
答案1
得分: 2
json
标签是属于编组逻辑还是json模型的问题存在争议。我认为,指定json标签只是描述json模型,因此最好将其放在Go模型旁边。
编组/解组逻辑是在encoding/json
包中实现的。如果需要自定义逻辑,可以通过实现json.Marshaler
和json.Unmarshaler
接口来指定/实现。这意味着需要为类型定义方法。在Go中,只能为同一包中的类型指定方法,因此如果将模型与自定义解析逻辑分开,解析包将无法为模型类型定义方法。规范:方法声明:
> T
所表示的类型称为接收器的基本类型;它不能是指针或接口类型,并且必须在同一包中声明。
也就是说,您需要在不同的类型上定义自定义解析逻辑,并且需要进一步的逻辑来映射/复制到模型类型作为解析逻辑的一部分。通过将模型与解析逻辑分开,您将失去更多而不是获得更多。
进一步说,您编组到的结构类型可能包含未导出的字段,如果解析逻辑在同一包中,可以正确初始化这些字段。通过分离模型和逻辑,逻辑将无法初始化未导出的字段。一种方法是提供导出的方法或函数,但这样会将它们导出给其他所有人,而不仅仅是解析逻辑。
我认为Go的方式和最简单的方式是将模型和解析逻辑放在同一个包中。这仍然给您提供了一种“小型”分离的可能性:您可以将类型定义放在一个文件中(例如model.go
),并且可以将自定义解析逻辑(实现json.Marshaler
和json.Unmarshaler
的方法)放在另一个文件中(例如parse.go
),当然还是在同一个包中,但是将类型及其所有方法放在一个地方(一个文件中)可能更好。
英文:
It is arguable whether json
tags belong to marshaling logic or to json model. I would say specifying json tags just describe the json model and as such it may be better residing next to your Go model.
The marshaling / unmarshaling logic is implemented in the encoding/json
package itself. If you need custom logic, you can specify / implement that by implementing the json.Marshaler
and json.Unmarshaler
interfaces. This means defining methods to your type. In Go you can only specify methods to types being in the same package, so if you would separate your model from your custom parsing logic, the parsing package could not define methods to model types. Spec: Method declarations:
> The type denoted by T
is called the receiver base type; it must not be a pointer or interface type and it must be declared in the same package as the method.
That being said you would need to define your custom parsing logic on a different type, and you would need further logic to map / copy into the model type as part of the parsing logic. You would lose more than you would gain by separating the model from the parsing logic.
Going further, the struct type you marshal into may contain unexported fields which - if the parsing logic is in the same package - can be initialized properly. By separating model and logic, the logic would have troubles initializing unexported fields. One way would be to provide exported methods or functions, but then those are exported to everyone else, not just for the parsing logic.
I'd say the Go way and the easiest way is to put model and parsing logic into the same package. It still gives you a "small" separation possibility: you may put the type definition in one file (e.g. model.go
), and you may put custom parsing logic (methods implementing json.Marshaler
and json.Unmarshaler
) in another file (e.g. parse.go
) but in the same package of course, but it may be better to see a type and all its methods in one place (in one file).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论