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

在Go中,为什么JSON null有时不传递给解组JSON进行解码?,json,go,Json,Go,Go提供了编码/json.Unmarshaler接口,因此类型可以控制从json解码的方式。几乎在所有情况下,编码的JSON值都直接传递给UnmarshalJSON方法,但如果Unmarshaler是指针且JSON值为null,则不会传递。在这种情况下,指针被设置为nil,而根本不调用UnmarshalJSON。下面是一个例子: package main import ( "encoding/json" "fmt" ) type T string func (v *T) U

Go提供了
编码/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为“空”
a、 PT1指向“非空”
a、 PT2指向“空”
相反,它会打印

a.T为“空”
a、 PT1指向“非空”
a、 PT2为零

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

这是因为将指针设置为
nil
是处理JSON
null
的最常用方法,而
*T
解组JSON
方法本身无法做到这一点。如果在本例中调用了
UnmarshalJSON
,则必须定义
(**T).UnmarshalJSON
以将
*T
设置为
nil
。这将使最常见的情况变得非常尴尬


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

是的,如果您有JSON字符串“null”,您将获得引用类型的null值(在大多数语言中不是Go)。请不要问明显的问题,5分钟后自己回答。也许我比大多数人都笨,但我花了一天的大部分时间来弄清楚为什么这不是标准库中的bug。如果我没有使用专门设计用来覆盖默认解码规则的Go接口,那就很明显了。我不会走那么远。我的评论是基于你一问起就回答了这个问题。也许这对其他人会有帮助。我认为这是一个非常常见的事情,进入反序列化JSON虽然。