我有一个数据库架构,其中Age是可选。但是当在Go中时,通过我的RestFUL接口(interface),我将数据输出为JSON,我得到了非常丑陋的响应,例如{"ID":1,"Name":"John","age":{"Int64":0,"Valid":false}}
的年龄。我希望省略一个空值。我想念什么?
// CREATE TABLE users (
// id INT AUTO_INCREMENT PRIMARY KEY,
// name VARCHAR(50) NOT NULL,
// age INT
// );
// Age is optional
type user struct {
ID int `db:"id"`
Name string `db:"name"`
Age sql.NullInt64 `db:"age" json:"age,omitempty"`
}
func main() {
u := user{ID: 1, Name: "John"}
j, _ := json.Marshal(u)
fmt.Printf("%s", j)
}
// Expected: {"ID":1,"Name":"John"} since age is NULL/empty
https://play.golang.org/p/PS1-4Gw9h5u
最佳答案
之所以存在sql.NullInt64
是因为SQL的null
无法表示为Go的int
。这是第三个状态,不能用任何int
值表示。
一种解决方案是将这样的SQL值表示为*int
,但是在数据库中该值不是null
且这种分配不利于性能的情况下,将需要进行分配。
SQL包的设计者想出了NullInt64
解决方案,该解决方案将null的第三个状态编码为附加的Valid
bool 值。这不是一个好的解决方案,但却是我们所能得到的最好的解决方案。
我不确定是否可以为NullInt64
编写可以按预期工作的JSON marshaller。
编码到JSON时,仍然存在“第三状态”问题。使用,omitempty
时,也会省略0
int,因此如何从“不存在”/空值中分辨出0?
无论哪种方式,他们都没有为NullInt64
编写自定义编码器,因此它只是编码为它的结构。
您可以为NullInt64
创建一个别名类型,编写一个JSON编码器以编码您想要JSON的方式(您需要一个别名,因为您无法将方法添加到其他包的类型中)。您还需要在NullInt64
和sql.NullInt64
之间进行转换。