質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

2回答

441閲覧

GoでAPIリクエストの構造体が変化する

退会済みユーザー

退会済みユーザー

総合スコア0

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2018/01/09 06:08

編集2018/01/10 07:17

JSONをgoでMarshalしたいのですが、構造体によって定義されるので、レスポンスの構造が予想できないときって、どのようにすればいいのですか?

APIのレスポンスが

{ "users": [{ "id":1 "has_weapon":true "weapon": "gun" }, { "id":2 "has_weapon":false } ] }

のようなJSONが返ってくるときに

go

1type user struct { 2 ID int 3 HasWeapon bool 4 weapon string 5}

のようにマッピングしたとて、それをuとします。
このときに

go

1weapon = u.Weapon

とするとid=2のときはエラーが出て無理ですよね?
こういう場合ってどのように実装するべきですか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mattn

2018/01/09 08:09

もう少し詳しく説明して下さい。何を期待されておられるのか分かりません。
退会済みユーザー

退会済みユーザー

2018/01/10 07:13

追加説明しました。すみません。
guest

回答2

0

ベストアンサー

まず質問の JSON が壊れています。また struct のフィールドに json タグが付けられていません。

go

1package main 2 3import ( 4 "encoding/json" 5 "fmt" 6 "log" 7 "strings" 8) 9 10type user struct { 11 ID int `json:"id"` 12 HasWeapon bool `json:"has_weapon"` 13 Weapon string `json:"weapon"` 14} 15 16func main() { 17 s := ` 18{ "users": [{ 19 "id":1, 20 "has_weapon":true, 21 "weapon": "gun" 22 }, 23 { 24 "id":2, 25 "has_weapon":false 26 } 27 ] 28} 29 ` 30 31 var data struct { 32 U []user `json:"users"` 33 } 34 err := json.NewDecoder(strings.NewReader(s)).Decode(&data) 35 if err != nil { 36 log.Fatal(err) 37 } 38 for _, u := range data.U { 39 fmt.Println(u.ID, u.Weapon) 40 } 41}

https://play.golang.org/p/UoWkatWpkYP

これで動くはずです。

投稿2018/01/10 08:33

mattn

総合スコア5030

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/01/10 10:17

ありがとうございます。非常に理解しました!
guest

0

APIのリファレンスを見てもらえばわかると思いますが、
構造が変化してるのではなく省略された項目があるだけだと思います。
一般には構造が規定されているはずなんです。
構造が予想できないAPIは使いにくくてしょうがないので。

それでもなお未知の構造のJSONレスポンスをUnmarshalしたいときは
「interface{}」型で受けると取り込めます。

go

1b := []byte(`{"unknown":{}}`) // 未知のJSON 2var v interface{} 3if err := json.Unmarshal(b, &v); err != nil { 4 // エラーハンドリング 5} 6uk := v.(map[string]interface{})["unknown"].(map[string]interface{}) 7fmt.Println(uk)

型を明示しない場合、jsonの各型は以下のように対応しています。

JSONでのタイプGoでのタイプ
Objectmap[string]interface{}
Array[]interface{}
Booleanbool
Stringstring
Numberfloat64
nullnil

実際の値を取り出すにはタイプアサーションが必要です。

逆にMarshalしたい場合は表の右側を用意すれば任意のJSONを組み立てられます。

go

1v := map[string]interface{}{ 2 "unknown": map[string]interface{}{}, 3} 4b, err := json.Marshal(v) 5if err != nil { 6 // エラーハンドリング 7}

投稿2018/01/09 09:39

編集2018/01/09 15:08
nobonobo

総合スコア3367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/01/10 07:15

丁寧にありがとうございます。 質問文を追加したのですが、このようなケースでも使えますよね?
退会済みユーザー

退会済みユーザー

2018/01/10 07:16

質問文での`weapon`のように省略されるケースはどのように実装するべきですか? よろしくお願いいたします。
nobonobo

2018/01/10 08:43

mattnさんの回答がズバリですね。
退会済みユーザー

退会済みユーザー

2018/01/10 10:17

ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問