在我的项目中,我定义了结构,以便从JSON获取数据。
我尝试使用json.Unmarshal()函数。但是它不适用于自定义类型属性。

有这样的结构:

type TestModel struct {
    ID   NullInt `json:"id"`
    Name string  `json:"name"`
}

在其中,NullInt类型是通过MarshalJSON()UnmarshalJSON()函数的实现定义的:
// NullInt ...
type NullInt struct {
    Int   int
    Valid bool
}

// MarshalJSON ...
func (ni NullInt) MarshalJSON() ([]byte, error) {
    if !ni.Valid {
        return []byte("null"), nil
    }
    return json.Marshal(ni.Int)
}

// UnmarshalJSON ...
func (ni NullInt) UnmarshalJSON(b []byte) error {
    fmt.Println("UnmarshalJSON...")
    err := json.Unmarshal(b, &ni.Int)
    ni.Valid = (err == nil)
    fmt.Println("NullInt:", ni)
    return err
}

main()函数中,我实现了:
func main() {
    model := new(TestModel)
    JSON := `{
        "id": 1,
        "name": "model"
    }`
    json.Unmarshal([]byte(JSON), &model)
    fmt.Println("model.ID:", model.ID)
}


在控制台中,我得到了:
UnmarshalJSON...
NullInt: {1 true}
model.ID: {0 false}


如您所见,NullInt.UnmarshalJSON()被调用了,ni是我期望的,但是model.ID的值。
什么是实现UnmarshalJSON()函数的正确方法?

另外,当我设置:JSON := `{"name": "model"}`(不带id)时,控制台只是:
model.ID: {0 false}

就是说,没有调用UnmarshalJSON()函数,所以我没有以正确的方式获取model.ID的值。

最佳答案

UnmarshalJSON()需要修改接收器,因此必须使用指针接收器:

func (ni *NullInt) UnmarshalJSON(b []byte) error {
    // ...
}

接收方和所有参数只是副本,如果您不使用指针,则只能修改副本,方法返回后将丢弃该副本。如果使用指针接收器,那也只是一个副本,但是指向的值将是相同的,因此可以修改原始(指向的)对象。

为了保持一致性,还可以将指针接收器用于其其他方法。

通过此更改,它可以工作并输出(在Go Playground上尝试):
UnmarshalJSON...
NullInt: &{1 true}
model.ID: {1 true}

10-04 14:14