GoでJSONから構造体に変換するときに気をつけること

JSONライブラリにGoの構造体を投げ入れるとき、
* 構造体のエイリアスやフィールド名を大文字にしたらいいんだっけ、小文字にしたらいいんだっけ、
* jsonタグとフィールド名のどっちが優先的にマッピングの対象になるんだっけ、

と悩んだので、いろいろ実験してみました。

# 普通（？）
投げ入れるjsonのプロパティ名と受け取る構造体のフィールド名が完全に一致している場合は当然、期待通りマッピングできる

```go
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type User struct {
	Id   int
	Name string
}

func main() {
	src := `{"Id":3,"Name":"nao"}`

	u := new(User)
	err := json.Unmarshal([]byte(src), u)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", u)
}

// 出力結果：&{Id:3 Name:nao}
```

## jsonのkey値が小文字の場合
投げ入れるjsonのプロパティ名が小文字で受け取る構造体のフィールド名が大文字のときどうなるんでしょう。
頭文字の大小が違ってもマッピングできてますね！

```go

package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type User struct {
	Id   int
	Name string
}

func main() {
	src := `{"id":3,"name":"nao"}`

	u := new(User)
	err := json.Unmarshal([]byte(src), u)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", u)
}

// 出力結果：&{Id:3 Name:nao}
```

## 構造体フィールド名小文字にした場合
jsonのプロパティ名も小文字、構造体のフィールド名も小文字の場合はどうでしょう。
マッピングできてませんね。

フィールド名が小文字だとプライベートなフィールドとして認識されてしまいます。Userという構造体のフィールドid, nameはpackage mainの中でしか触ることができません。

package jsonに構造体のフィールドを渡すにはフィールド名を大文字始まりにしないといけません。
Goの基本文法ですが忘れてるとハマりがちですね。

```go
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type User struct {
	id   int
	name string
}

func main() {
	src := `{"id":3,"name":"nao"}`

	u := new(User)
	err := json.Unmarshal([]byte(src), u)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", u)
}

// 出力結果：&{id:0 name:}

```

## 構造体フィールド名とJSONキー名が不一致+jsonタグをつける
投げ入れられるjson名をそのままGoの世界で扱いたくないということはよくあります。


e.g. json名をGoの世界でそのまま使いたくないとき
* プロジェクトの命名規則と異なる。
* すでにnameという変数は使われていて名前がバッティングする。
* nameってなんの名前のこと指してるのかわからない。わかりやすいフィールド名にしたい。



そんなときはjsonタグをつけてやるとよいです。
投げ入れられるjsonのプロパティ名とjsonタグが一致していれば、構造体のフィールド名は好きに設定できます


```go
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type User struct {
	UserId   int `json:"id"`
	UserName string `json:"name"`
}

func main() {
	src := `{"id":3,"name":"nao"}`

	u := new(User)
	err := json.Unmarshal([]byte(src), u)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", u)
}

// 出力結果：&{UserId:3 UserName:nao}
```

## 構造体名を小文字
フィールド名は大文字始まりじゃないといけないみたいですが、構造体名自体は小文字始まりでよいみたいです。。。

```go
import (
	"encoding/json"
	"fmt"
	"log"
)

type user struct {
	UserId   int `json:"id"`
	UserName string `json:"name"`
}

func main() {
	src := `{"id":3,"name":"nao"}`

	u := new(user)
	err := json.Unmarshal([]byte(src), u)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", u)
}

// 出力結果：&{UserId:3 UserName:nao}
```

## jsonタグ名とJSONキー名の大文字小文字は適当でいい

わざわざそんなことする必要もないですが。。。

```go
import (
	"encoding/json"
	"fmt"
	"log"
)

type user struct {
	UserId   int `json:"Id"`
	UserName string `json:"nAme"`
}

func main() {
	src := `{"id":3,"NamE":"nao"}`

	u := new(user)
	err := json.Unmarshal([]byte(src), u)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", u)
}

// 出力結果：&{UserId:3 UserName:nao}
```

### そもそも構造体のエイリアスを設定する必要はない

手軽にJSONからデータを取り出したいなら

```go
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

func main() {
	src := `{"id":3,"name":"nao"}`

	u := &struct{UserName string `json:"name"`}{}
	err := json.Unmarshal([]byte(src), u)
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Printf("%+v\n", u)
}

// 出力結果：&{UserName:nao}