encoding/json と構造体
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 76/107。
encoding/jsonパッケージを使用すると、Goの構造体をJSONに変換したり、その逆に変換したりできます。これは、API、設定ファイル、およびデータストレージにとって不可欠です。構造体タグは、フィールドがJSONキーにどのようにマッピングされるかを制御します。
構造体をJSONに変換するには、json.Marshalを使用します:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
func main() {
user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
data, _ := json.Marshal(user)
fmt.Println(string(data))
// {"name":"Alice","email":"alice@example.com","age":30}
}`json:"name"` のような構造体タグは、JSONのキー名を指定します。タグがない場合、Goはフィールド名をそのまま使用します。エクスポートされたフィールド(大文字で始まるもの)のみがJSON出力に含まれます。
JSONを構造体に戻すには、json.Unmarshalを使用します:
jsonStr := `{"name":"Bob","email":"bob@example.com","age":25}`
var user User
json.Unmarshal([]byte(jsonStr), &user)
fmt.Println(user.Name) // Bob一般的なタグのオプションには、ゼロ値をスキップするための omitempty や、フィールドを完全に無視するための - が含まれます:
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Price float64 `json:"price,omitempty"`
Internal string `json:"-"`
}omitempty を使用すると、Price がゼロの場合、JSON には表示されません。Internal フィールドは、その値に関係なく、決して含まれません。
チャレンジ
簡単Goの構造体とJSONを相互に変換する映画カタログシステムを構築しましょう!構造体をJSONにマーシャリングし、JSONを構造体にアンマーシャリングする練習をします。その際、構造体タグを使用してJSONのフィールド名を制御します。
コードは2つのファイルに分けて構成します:
movie.go: 適切なJSONタグを使用して映画データモデルを定義します。以下のフィールドとJSONマッピングを持つ
Movie構造体を作成してください:Title(string) は"title"にマッピングDirector(string) は"director"にマッピングYear(int) は"year"にマッピングRating(float64) は"rating"にマッピングし、評価のない映画にratingフィールドが表示されないようomitemptyを指定InternalID(string) は"-"を使用してJSONから完全に除外
MovieをJSON文字列に変換する関数
ToJSON(m Movie) stringを作成してください。また、JSON文字列をMovie構造体にパースするFromJSON(jsonStr string) Movieも作成してください。main.go: 両方向のJSON変換を実演します。操作タイプ(
encodeまたはdecode)を読み取ります。encodeの場合:映画の詳細(タイトル、監督、公開年、評価)を別々の行で読み取ります。InternalIDを"internal-123"としたMovieを作成し、それをJSONに変換して結果を出力します。decodeの場合:JSON文字列を読み取り、Movie構造体に変換して、映画の詳細を以下の形式で出力します:Title: [title] Director: [director] Year: [year] Rating: [rating]評価は小数点以下1位まで表示してください。評価が0(JSONに存在しない)の場合は、代わりに
Rating: N/Aと出力してください。
以下の入力が提供されます:
- 1行目:操作タイプ(
encodeまたはdecode) - encodeの場合:タイトル、監督、公開年、評価(4行)
- decodeの場合:JSON文字列(1行)
例えば、以下が与えられた場合:
encode
Inception
Christopher Nolan
2010
8.8出力は以下のようになります:
{"title":"Inception","director":"Christopher Nolan","year":2010,"rating":8.8}"-" タグのため、出力に InternalID が表示されないことに注目してください。
また、以下が与えられた場合:
encode
The Matrix
Wachowskis
1999
0出力は以下のようになります:
{"title":"The Matrix","director":"Wachowskis","year":1999}値がゼロで omitempty が指定されているため、rating が省略されていることに注目してください。
また、以下が与えられた場合:
decode
{"title":"Interstellar","director":"Christopher Nolan","year":2014,"rating":8.6}出力は以下のようになります:
Title: Interstellar
Director: Christopher Nolan
Year: 2014
Rating: 8.6また、以下が与えられた場合:
decode
{"title":"Tenet","director":"Christopher Nolan","year":2020}出力は以下のようになります:
Title: Tenet
Director: Christopher Nolan
Year: 2020
Rating: N/Aチートシート
encoding/json パッケージは、json.Marshal と json.Unmarshal を使用して Go の構造体を JSON に、またはその逆に変換します。
構造体を JSON に変換するには:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
data, _ := json.Marshal(user)
fmt.Println(string(data))
// {"name":"Alice","email":"alice@example.com","age":30}JSON を構造体に戻すには:
jsonStr := `{"name":"Bob","email":"bob@example.com","age":25}`
var user User
json.Unmarshal([]byte(jsonStr), &user)
fmt.Println(user.Name) // Bob構造体タグは JSON フィールドのマッピングを制御します:
`json:"name"`- フィールドを JSON キー "name" にマッピングします`json:"price,omitempty"`- 値がゼロ値の場合、フィールドを省略します`json:"-"`- フィールドを JSON から完全に除外します
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Price float64 `json:"price,omitempty"`
Internal string `json:"-"`
}エクスポートされたフィールド(大文字で始まるもの)のみが JSON 出力に含まれます。
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// 操作タイプを読み込む
operation, _ := reader.ReadString('\n')
operation = strings.TrimSpace(operation)
if operation == "encode" {
// 映画の詳細を読み込む
title, _ := reader.ReadString('\n')
title = strings.TrimSpace(title)
director, _ := reader.ReadString('\n')
director = strings.TrimSpace(director)
yearStr, _ := reader.ReadString('\n')
yearStr = strings.TrimSpace(yearStr)
year, _ := strconv.Atoi(yearStr)
ratingStr, _ := reader.ReadString('\n')
ratingStr = strings.TrimSpace(ratingStr)
rating, _ := strconv.ParseFloat(ratingStr, 64)
// TODO: 読み込んだ値を使用して Movie 構造体を作成する
// InternalID を "internal-123" に設定する
// ToJSON を使用して JSON に変換し、結果を出力する
} else if operation == "decode" {
// JSON 文字列を読み込む
jsonStr, _ := reader.ReadString('\n')
jsonStr = strings.TrimSpace(jsonStr)
// TODO: FromJSON を使用して JSON を Movie に変換する
// 必要な形式で映画の詳細を出力する
// 評価のフォーマットには fmt.Sprintf("%.1f", rating) を使用する
// rating が 0 の場合は、代わりに "Rating: N/A" を出力する
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー11標準ライブラリとOOP
io.Reader と io.Writersort.Interfacefmt.Stringer インターフェースencoding/json と構造体http.Handler インターフェースまとめ:REST API モデル