在Go中,为什么JSON null有时不会传递给UnmarshalJSON进行解码?

时间:2015-12-08 18:46:07

标签: json go

Go提供encoding/json.Unmarshaler接口,因此类型可以控制它们从JSON解码的方式。几乎在所有情况下,编码的JSON值都直接传递给UnmarshalJSON方法,但如果Unmarshaler是指针且JSON值为null则不会。在这种情况下,指针设置为nil而根本不调用UnmarshalJSON。这是一个例子:

package main

import (
    "encoding/json"
    "fmt"
)

type T string

func (v *T) UnmarshalJSON(b []byte) error {
    if b[0] == 'n' {
        *v = "null"
    } else {
        *v = "not null"
    }
    return nil
}

func main() {
    var a struct {
        T   T
        PT1 *T
        PT2 *T
    }
    a.PT1 = nil // just to be explicit
    a.PT2 = new(T)
    err := json.Unmarshal([]byte(`{"T":null,"PT1":"foo","PT2":null}`), &a)
    if err != nil {
        panic(err)
    }
    fmt.Printf("a.T is %#v\n", a.T)
    if a.PT1 == nil {
        fmt.Println("a.PT1 is nil")
    } else {
        fmt.Printf("a.PT1 points to %#v\n", *a.PT1)
    }
    if a.PT2 == nil {
        fmt.Println("a.PT2 is nil")
    } else {
        fmt.Printf("a.PT2 points to %#v\n", *a.PT2)
    }
}

我希望打印

a.T is "null"
a.PT1 points to "not null"
a.PT2 points to "null"

相反,它打印

a.T is "null"
a.PT1 points to "not null"
a.PT2 is nil

因此json.UnmarshalT分配了一个新的a.PT1,最初为nil。但是,即使a.PT2不是nil,它也会UnmarshalJSON设置为a.PT2而不会调用nil。为什么呢?

1 个答案:

答案 0 :(得分:1)

这是因为将指针设置为nil是处理JSON null的最常用方法,UnmarshalJSON方法无法*T这样做。如果在这种情况下调用UnmarshalJSON,您必须定义(**T).UnmarshalJSON以将*T设置为nil。这将使最常见的情况非常尴尬。

如果您不希望JSON null成为Go nil,请不要使用指针。