我有一个数据库架构,其中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的方式(您需要一个别名,因为您无法将方法添加到其他包的类型中)。您还需要在NullInt64sql.NullInt64之间进行转换。

10-07 15:26