言語バージョン 1.15.6

公開日 February 27, 2021, GMT+9

json.Unmarshal

このページでは豊富な例を用いてGolangのjsonパッケージのUnmarshal関数の使い方を学ぶことができます。

Unmarshal関数はjsonパッケージの関数の1つです。
第1引数で与えたJSONデータを第2引数で指定した値にマッピングします。
返り値としてerror型の値を返し、エラーが発生しない場合はnilとなります。

// 記述例

import "encoding/json"

エラー := json.Unmarshal(JSONデータ, マッピングされる値)

TL;DR

基本

// 第1引数にJSONデータ、第2引数にJSONデータをマッピングする値を指定する

// JSONデータの生成
jsonData1 := []byte(`{
  "ID": 1,
  "Name": "Alex"
}`)

type Person struct {
  ID   int
  Name string
}

// JSONデータのマッピング(第2引数にポインタを渡す)
var person1 Person
err := json.Unmarshal(jsonData1, &person1)
if err != nil {
  fmt.Println(err)
}
fmt.Printf("%+v\n", person1)
==> {ID:1 Name:Alex}






// JSONデータのキーの大文字・小文字に関係なくマッピングされる
jsonData2 := []byte(`{
  "id": 1,
  "namE": "Alex"
}`)
var person2 Person
if err := json.Unmarshal(jsonData2, &person2); err != nil {
  fmt.Println(err)
}
fmt.Printf("%+v\n", person2)
==> {ID:1 Name:Alex}






// Unmarshalの第2引数にポインタが渡されないとエラー
jsonData3 := []byte(`{
  "ID": 1,
  "Name": "Alex"
}`)
var person3 Person
if err := json.Unmarshal(jsonData3, person3); err != nil {
  fmt.Println(err)
}
==> (エラー)json: Unmarshal(non-pointer (パッケージ名).Person)
fmt.Printf("%+v\n", person3)
==> {ID:0 Name:}






// 配列型のJSONの場合
jsonData4 := []byte(`["go", "golang"]`)
var array4 []string
if err := json.Unmarshal(jsonData4, &array4); err != nil {
  fmt.Println(err)
}
fmt.Printf("%+v\n", array4)
==> [go golang]





// マップ(map)にマッピングする場合
jsonData5 := []byte(`{"go": 0, "golang": 1}`)
var map5 map[string]int
_ = json.Unmarshal(jsonData5, &map5)
fmt.Printf("%+v\n", map5)
==> map[go:0 golang:1]





// interface{}型の変数にマッピングする場合
jsonData6 := []byte(`{
  "ID": 1,
  "Name": "Alex",
  "Friends": ["Olivia", "Xiaoran"]
}`)
var interface6 interface{}
_ = json.Unmarshal(jsonData6, &interface6)
fmt.Printf("%+v\n", interface6)
==> map[Friends:[Olivia Xiaoran] ID:1 Name:Alex]

// 型はキーがstring、値がinterface{}のマップとなる
fmt.Printf("%T\n", interface6)
==> map[string]interface {}

関連情報:array型(配列)の解説

関連情報:map型(マップ)の解説

フィールド名とフィールドタグによるマッピング挙動

// 同一パッケージ外からアクセスできない構造体のフィールド(Non-exported field、最初が大文字ではないフィールド)はマッピングされない
type Language struct {
  ID   int
  name string
}

jsonData1 := []byte(`{
  "ID": 1,
  "name": "Hindi"
}`)
var language1 Language
_ = json.Unmarshal(jsonData1, &language1)
fmt.Printf("%+v\n", language1)
==> {ID:1 name:}






// フィールドタグで指定されている名前がマッピングされる
type Language2 struct {
  ID   int    `json:"lang_id"`
  Name string `json:"lang_name"`
}

// JSONのキー名がフィールドタグと異なるとマッピングされない
jsonData2 := []byte(`{
  "ID": 2,
  "Name": "Chinese"
}`)
var language2 Language2
_ = json.Unmarshal(jsonData2, &language2)
fmt.Printf("%+v\n", language2)
==> {ID:0 Name:}

// JSONのキー名がフィールドタグと一致する場合
jsonData3 := []byte(`{
  "lang_id": 2,
  "lang_name": "Chinese"
}`)
var language3 Language2
_ = json.Unmarshal(jsonData3, &language3)
fmt.Printf("%+v\n", language3)
==> {ID:2 Name:Chinese}

マッピングされなかったフィールドの扱い

type Person struct {
  Name      string
  Age       int
  IsStudent bool
  Friends   []string
}

// JSONのキーにマッピング対象のフィールドが存在しない場合はゼロ値(zero value)が割り当てられる
jsonData1 := []byte(`{
  "FooBarNinja": true
}`)
var person1 Person
_ = json.Unmarshal(jsonData1, &person1)
fmt.Printf("%+v\n", person1)
==> {Name: Age:0 IsStudent:false Friends:[]}






// JSONに存在しないフィールドをnilにしたい場合
type Person2 struct {
  Name      *string
  Age       *int
  IsStudent *bool
  Friends   *[]string
}

jsonData2 := []byte(`{
  "FooBarNinja": true
}`)
var person2 Person2
_ = json.Unmarshal(jsonData2, &person2)
fmt.Printf("%+v\n", person2)
==> {Name:<nil> Age:<nil> IsStudent:<nil> Friends:<nil>}

JSONへの変換

type Guest struct {
  ID   int
  Name string
}

// JSONから構造体へのマッピング
jsonData1 := []byte(`{
  "id": 1,
  "name": "Johnson"
}`)
var guest1 Guest
_ = json.Unmarshal(jsonData1, &guest1)
fmt.Printf("%+v\n", guest1)
==> {ID:1 Name:Johnson}

// 構造体からJSONへの変換
encodedJson, err := json.Marshal(guest1)
if err != nil {
  fmt.Println(err)
}
fmt.Printf("%s\n", encodedJson)
==> {"ID":1,"Name":"Johnson"}

関連情報:json.Marshalの使用方法

解説

// 記述例

import "encoding/json"

エラー := json.Unmarshal(JSONデータ, マッピングされる値)

基本

Unmarshal関数はJSONデータを値にマッピングすることができます。

第1引数に「マッピングしたいJSONデータ([]byte型)」を、第2引数に「マッピングされる値(interface{}型)のポインタ」を指定します。
第2引数にポインタを指定しない場合、エラーが発生してJSONデータがマッピングされません。

返り値はerror型の値が返り、エラーが発生しない場合は返り値はnilとなります。

マッピングされるJSONデータのキーは、マッピングされるフィールドの大文字・小文字が完全に一致しなくともマッピングされます。

// マッピング元のJSONデータ
jsonData1 := []byte(`{
  "Name": "Kiwi",
  "Price": 100
}`)

type Fruit struct {
  Name  string
  Price int
}

var fruit1 Fruit
err := json.Unmarshal(jsonData1, &fruit1)
if err != nil {
  fmt.Println(err)
}
fmt.Printf("%+v\n", fruit1)
==> {Name:Kiwi Price:100}






// JSONデータのキーの大文字・小文字に関係なくマッピングされる
jsonData2 := []byte(`{
  "name": "Kiwi",
  "price": 100
}`)
var fruit2 Fruit
if err := json.Unmarshal(jsonData2, &fruit2); err != nil {
  fmt.Println(err)
}
fmt.Printf("%+v\n", fruit2)
==> {Name:Kiwi Price:100}






// 第2引数にポインタが渡されないとエラー
jsonData3 := []byte(`{
  "name": "Apple",
  "price": 200
}`)
var fruit3 Fruit
if err := json.Unmarshal(jsonData3, fruit3); err != nil {
  fmt.Println(err)
}
==> (エラー)json: Unmarshal(non-pointer (パッケージ名).Fruit)
fmt.Printf("%+v\n", fruit3)
==> {Name: Price:0}






// 配列型のJSONからのマッピング
jsonData4 := []byte(`[true, true, false]`)
var array4 []bool
_ = json.Unmarshal(jsonData4, &array4)
fmt.Printf("%+v\n", array4)
==> [true true false]






// マップ(map)へのマッピング
jsonData5 := []byte(`{"go": "Go", "golang": "Golang"}`)
var map5 map[string]string
_ = json.Unmarshal(jsonData5, &map5)
fmt.Printf("%+v\n", map5)
==> map[go:Go golang:Golang]






// interface{}型へのマッピング
jsonData6 := []byte(`{
  "Name": "Banana",
  "Price": 300,
  "Discount": {
    "Type": "weekend"
  }
}`)
var interface6 interface{}
_ = json.Unmarshal(jsonData6, &interface6)
fmt.Printf("%+v\n", interface6)
==> map[Discount:map[Type:weekend] Name:Banana Price:300]

// 型はキーがstring、値がinterface{}のマップ
fmt.Printf("%T\n", interface6)
==> map[string]interface {}

関連情報:array型(配列)の解説

関連情報:map型(マップ)の解説

フィールド名とフィールドタグによるマッピング挙動

構造体(struct)の「小文字から始まる名前を持つフィールド(Non-exported field)」は外部パッケージからアクセスすることができません。
このようなフィールドはUnmarshal関数を使用してマッピングした場合もJSONデータはマッピングされず、ゼロ値が設定されます。

また、構造体のフィールドタグにjsonというキーが指定されている場合、 JSONデータから第2引数にマッピングされるものは「フィールドタグで指定した名前」と一致するものだけです。

// 同一パッケージ外からアクセスできない構造体フィールド(Non-exported field、最初が大文字ではないフィールド)にマッピングする場合
type Student struct {
  Name  string
  score int
}

jsonData1 := []byte(`{
  "Name": "Anika",
  "score": 100
}`)
var student1 Student
_ = json.Unmarshal(jsonData1, &student1)
// scoreのJSONデータはマッピングされず、intのゼロ値である0が割り当てられる
fmt.Printf("%+v\n", student1)
==> {Name:Anika score:0}






// フィールドタグでjsonのキー名が指定されている場合
type Student2 struct {
  Name  string `json:"student_name"`
  Score int    `json:"student_score"`
}

// jsonのキー名とフィールドタグが一致する値のみマッピングされる
jsonData2 := []byte(`{
  "Name": "Anika",
  "student_score": 100
}`)
var student2 Student2
_ = json.Unmarshal(jsonData2, &student2)
fmt.Printf("%+v\n", student2)
==> {Name: Score:100}

マッピングされなかったフィールドの扱い

JSONデータ内にフィールドに値するデータが存在せず、第2引数にマッピングされなかった第2引数のフィールドは、 ゼロ値(zero value)と呼ばれる値に設定されます。
ゼロ値がどのような値であるかはフィールドに指定した型によって異なります。

マッピングされなかったフィールドをゼロ値で設定したくない場合、構造体のフィールドの型をポインタにするなどの方法があります。
フィールドの型をポインタにする場合、マッピングされなかったフィールドにはnilが設定されます。

type Student struct {
  ID            int
  Name          string
  IsScholarship bool
  Subjects      []string
}

jsonData1 := []byte(`{
  "FooBarNinja": true
}`)
var student1 Student
_ = json.Unmarshal(jsonData1, &student1)
fmt.Printf("%+v\n", student1)
==> {ID:0 Name: IsScholarship:false Subjects:[]}






// マッピングされないフィールドをnilにしたい場合
type Student2 struct {
  ID            *int
  Name          *string
  IsScholarship *bool
  Subjects      *[]string
}

jsonData2 := []byte(`{
  "FooBarNinja": true
}`)
var student2 Student2
_ = json.Unmarshal(jsonData2, &student2)
fmt.Printf("%+v\n", student2)
==> {ID:<nil> Name:<nil> IsScholarship:<nil> Subjects:<nil>}

JSONへの変換

Unmarshal関数は「JSONデータを他の値にマッピングする関数」ですが、同じjsonパッケージのMarshal関数は反対に「値をJSONへと変換する関数」です。

コード例にMarshal関数の使用方法を簡潔に記載しました。
より詳しく知りたい場合は以下のリンクを参照してください。 。

関連情報:json.Marshalの使用方法

type Person struct {
  ID     int
  Height float64
}

// JSONから構造体へのマッピング
jsonData1 := []byte(`{
  "id": 1,
  "height": 176.5
}`)
var person1 Person
_ = json.Unmarshal(jsonData1, &person1)
fmt.Printf("%+v\n", person1)
==> {ID:1 Height:176.5}

// 構造体からJSONへの変換
encodedJson, err := json.Marshal(person1)
if err != nil {
  fmt.Println(err)
}
fmt.Printf("%s\n", encodedJson)
==> {"ID":1,"Height":176.5}

1次情報

func Unmarshal - The Go Programming Language

JSON and Go - The Go Blog

Exported identifiers - The Go Programming Language