JSON永続化レイヤー
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 102/107。
チャレンジ
簡単図書館管理システムにデータの永続性を追加しましょう!ライブラリのデータを保存用にJSON形式に変換し、JSON文字列から読み戻すことができるJSON永続化レイヤーを実装します。これは、セッション間でデータを保持する必要がある実際のアプリケーションにとって不可欠です。
コードを5つのファイルに分けて構成します:
book.go: シリアル化を制御するためのJSON構造体タグを持つBook構造体。各フィールドには、対応するJSONタグid,title,author,isbn,availableを持たせる必要があります。NewBookコンストラクタを含めてください。user.go:id,name,email,borrowed_books用のJSON構造体タグを持つUser構造体。NewUserコンストラクタを含めてください。data.go: JSONシリアル化のための転送オブジェクトとして機能するLibraryData構造体を作成します。これには、Books(Bookポインタのスライス)とUsers(Userポインタのスライス)の2つのフィールドがあり、それぞれ適切なJSONタグ(booksとusers)が付いている必要があります。library.go: 本とユーザーのマップを持つLibrary構造体。2つの新しいメソッドを追加します:ToJSON()— 2つのスペースのインデントでjson.MarshalIndentを使用して、ライブラリのデータをフォーマットされたJSON文字列に変換します。マップからすべての本とユーザーをLibraryData構造体に収集し、それをシリアル化する必要があります。FromJSON(jsonStr string)— JSON文字列を受け取り、それをLibraryData構造体にアンマシュール(復元)し、読み込まれた本とユーザーでライブラリのマップを埋めます。
main.go: ライブラリを構築し、それをJSONに変換することで永続化レイヤーを実演します。本の数を読み取り、次に各本についてID、タイトル、著者、ISBNを読み取ります。次に、ユーザーの数を読み取り、各ユーザーについてID、名前、メールアドレスを読み取ります。ライブラリにデータを入力した後、
ToJSON()を呼び出し、結果のJSON文字列を出力します。
以下の入力が提供されます:
- 本の数、次に各本のID、タイトル、著者、ISBN(それぞれ個別の行)
- ユーザーの数、次に各ユーザーのID、名前、メールアドレス(それぞれ個別の行)
例えば、以下が与えられた場合:
2
B001
The Go Programming Language
Alan Donovan
978-0134190440
B002
Clean Code
Robert Martin
978-0132350884
1
U001
Alice Smith
alice@library.com出力は以下のようになります:
{
"books": [
{
"id": "B001",
"title": "The Go Programming Language",
"author": "Alan Donovan",
"isbn": "978-0134190440",
"available": true
},
{
"id": "B002",
"title": "Clean Code",
"author": "Robert Martin",
"isbn": "978-0132350884",
"available": true
}
],
"users": [
{
"id": "U001",
"name": "Alice Smith",
"email": "alice@library.com",
"borrowed_books": []
}
]
}また、以下が与えられた場合:
1
B100
Design Patterns
Gang of Four
978-0201633610
0出力は以下のようになります:
{
"books": [
{
"id": "B100",
"title": "Design Patterns",
"author": "Gang of Four",
"isbn": "978-0201633610",
"available": true
}
],
"users": []
}重要: スライスを構築するためにマップを反復処理するときは、本を B001, B002 などの順序(IDのアルファベット順)で追加し、ユーザーも同様に追加してください。これにより、一貫したJSON出力が保証されます。反復処理の前に、マップのキーに対して sort.Strings を使用できます。
LibraryData 構造体は、マップベースのストレージとJSONの配列ベースのフォーマットの間のギャップを埋めます。この転送オブジェクトパターンは、複雑なデータ構造をシリアル化するときによく使われます!
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// 新しいライブラリを作成する
library := NewLibrary()
// 本の数を読み込む
numBooksStr, _ := reader.ReadString('\n')
numBooks, _ := strconv.Atoi(strings.TrimSpace(numBooksStr))
// TODO: 各本の詳細(ID、タイトル、著者、ISBN)を読み込む
// そしてそれらをライブラリに追加する
for i := 0; i < numBooks; i++ {
// TODO: 本のIDを読み込む
// TODO: 本のタイトルを読み込む
// TODO: 本の著者を読み込む
// TODO: 本のISBNを読み込む
// TODO: 本を作成してライブラリに追加する
}
// ユーザーの数を読み込む
numUsersStr, _ := reader.ReadString('\n')
numUsers, _ := strconv.Atoi(strings.TrimSpace(numUsersStr))
// TODO: 各ユーザーの詳細(ID、名前、email)を読み込む
// そしてそれらをライブラリに追加する
for i := 0; i < numUsers; i++ {
// TODO: ユーザーIDを読み込む
// TODO: ユーザー名を読み込む
// TODO: ユーザーのemailを読み込む
// TODO: ユーザーを作成してライブラリに追加する
}
// TODO: ライブラリをJSONに変換して出力する
fmt.Println(library.ToJSON())
}
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー