GoのStructをJSONに変換する場合fieldは大文字でなければならない

GoでJSONを扱いたかったのだがStructから変換する際に変換の対象にならないFieldがあった。

type User struct {
    No int
    Name string
    tel string
}

func main() {
    user := User{No: 0, Name: "Bob", tel: "000-1111-2222"}
    json, _ := json.Marshal(user)
    fmt.Println(string(json)) // {"No":0,"Name":"Bob"}
}

要はStructのFIeldが小文字で始まる場合はJSONへのコンバートの対象にならないようだ。

どうやらGoは定数なども頭文字を大文字にしないと外部のパッケージからアクセス出来ず、その関係なのかJSONに変換させる際にも大文字で始める必要があるらしい。

pkg.go.dev

users []string // not exported

JSONに変換したい時にはStructのKeyを全部大文字にしないといけないのは無茶だろうと思ったが、StructにはTagオプションがありJSONに変換する際のKeyの指定や値が空の場合に変換の候補から外すオプション(omitempty)などが指定出来るようなのでこれを使うという事のようだ。

Name string json:"name,omitempty"

Tagをつければ小文字始まりのKeyでもJSONとして出力できる。

type User struct {
    No   int
    Name string
    Tel  string `json:"tel"`
}

func main() {
    user := User{No: 0, Name: "Bob", Tel: "000-1111-2222"}
    json, _ := json.Marshal(user)
    fmt.Println(string(json)) // {"No":0,"Name":"Bob","tel":"000-1111-2222"}
}

この状態でStructに値を指定しなければJSONに変換した際に空文字で出力されるが

user := User{No: 0, Name: "Bob"}
Tel string `json:"tel"` // {"No":0,"Name":"Bob","tel":""}

TagにomitemptyのオプションをつければJSONのKey自体が省略される

Tel string `json:"tel,omitempty"` // {"No":0,"Name":"Bob"}

Goをそんなに書き慣れていないのでJSONにした際に一部だけ落ちるという状況に最初?となったが、頭文字が大文字か小文字かでエクスポートの対象にするか分けるという事が分かればルールとしてなるほどと思うで言語の仕様としてちょっと面白いと感じた。

言語を調べる際にはなるべく公式にあたりたいと思うのだがGoのpkgは日本語のドキュメントがあるがStructに関しては適当なものが見つからず途中ちょっと困った。