encoding/json עם מבנים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 76 מתוך 107.
החבילה encoding/json מאפשרת לך להמיר מבני Go ל-JSON ולהפך. זה חיוני לממשקי API, לקובצי תצורה ולאחסון נתונים. תגיות של מבנים קובעות כיצד שדות ממופים למפתחות JSON.
כדי להמיר struct ל-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.
תארגנו את הקוד שלכם בשני קבצים:
movie.go: הגדירו את מודל הנתונים של הסרט עם תגיות JSON מתאימות.צרו מבנה
Movieעם השדות והמיפויים ל-JSON הבאים:Title(מחרוזת) ממופה ל-"title"Director(מחרוזת) ממופה ל-"director"Year(מספר שלם) ממופה ל-"year"Rating(מספר ממשי מסוג float64) ממופה ל-"rating"עםomitempty, כך שסרטים ללא דירוג לא יציגו שדה דירוג- יש להחריג את
InternalID(מחרוזת) לחלוטין מ-JSON באמצעות"-"
צרו פונקציה
ToJSON(m Movie) stringשממירה Movie למחרוזת JSON. צרו גם אתFromJSON(jsonStr string) Movie, שמנתחת מחרוזת JSON בחזרה למבנה Movie.main.go: הדגימו המרת JSON בשני הכיוונים.קראו סוג פעולה (
encodeאוdecode).עבור
encode: קראו את פרטי הסרט (כותרת, במאי, שנה, דירוג) בשורות נפרדות. צרו Movie עם InternalID שערכו"internal-123", המירו אותו ל-JSON והדפיסו את התוצאה.עבור
decode: קראו מחרוזת JSON, המירו אותה למבנה Movie והדפיסו את פרטי הסרט בפורמט הבא:Title: [title] Director: [director] Year: [year] Rating: [rating]הציגו את הדירוג עם ספרה אחת אחרי הנקודה העשרונית. אם הדירוג הוא 0 (אינו מופיע ב-JSON), הדפיסו
Rating: N/Aבמקום זאת.
הקלטים הבאים יסופקו:
- שורה 1: סוג פעולה (
encodeאוdecode) - עבור encode: כותרת, במאי, שנה, דירוג (ארבע שורות)
- עבור decode: מחרוזת JSON (שורה אחת)
לדוגמה, בהינתן:
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}שימו לב ש-rating מושמט משום שהוא אפס ויש לו omitempty.
ובהינתן:
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נסו בעצמכם
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: צור struct מסוג Movie עם הערכים שנקראו
// הגדר את InternalID ל-"internal-123"
// המר ל-JSON באמצעות ToJSON והדפס את התוצאה
} else if operation == "decode" {
// קרא מחרוזת JSON
jsonStr, _ := reader.ReadString('\n')
jsonStr = strings.TrimSpace(jsonStr)
// TODO: המר JSON ל-Movie באמצעות FromJSON
// הדפס את פרטי הסרט בפורמט הנדרש
// השתמש ב-fmt.Sprintf("%.1f", rating) כדי לעצב את rating
// אם rating הוא 0, הדפס במקום זאת "Rating: N/A"
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP ב-Go
קבצים חיצונייםסביבת העבודה והמודולים של Goחבילות וייבואשמות מיוצאים לעומת שמות לא מיוצאיםמבוא ל-OOP ב-GoStructs כמחלקותהגדרת מתודות עבור Structsמקבלי Pointer לעומת Valueאתחול Structפונקציות Constructorחזרה – מחשבון פשוט4ממשקים
מבוא לממשקיםמימוש משתמעממשק כחוזהממשק ריק (any)אימות טיפוסמתג טיפוסיםהרכבת ממשקיםממשקי Stringer ו-Errorסיכום – מחשבון צורות7כימוס
שדות מיוצאים לעומת שדות לא מיוצאיםכימוס ברמת החבילהמתודות Getter ו-Setterהסתרת מידע ב-Goסיכום – רשומות תלמידים10Generics (Go 1.18 ומעלה)
מבוא ל־Genericsפרמטרים של טיפוסיםאילוצי טיפוסיםמבנים גנרייםפתרון עוקף למתודות גנריותסיכום – אוסף גנרי2העמקה בסוגים וב-Structs
סוגים בסיסיים ומורכביםהגדרות של סוגים מותאמים אישיתתגיות StructStructs אנונימייםStructs מקונניםערכי אפס וברירות מחדלסיכום – ספר אנשי קשר5קומפוזיציה במקום ירושה
למה ב-Go אין ירושהיסודות הטמעת Structקידום מתודותהטמעת כמה Structsהטמעה לעומת אגרגציההסתרת מתודות מוטמעותסיכום – היררכיית עובדים8טיפול בשגיאות ו-OOP
ממשק errorסוגי שגיאות מותאמים אישיתעטיפת שגיאות (fmt.Errorf)שגיאות Sentinelerrors.Is() ו-errors.As()Panic, Defer ו-Recoverסיכום – מנתח קבצים11ספרייה סטנדרטית ותכנות מונחה עצמים
io.Reader ו-io.Writersort.Interfaceהממשק fmt.Stringerencoding/json עם מבניםהממשק http.Handlerסיכום – מודלים של REST API3מצביעים וזיכרון
יסודות המצביעים ב-Goמצביעים למבניםהעברה לפי ערך לעומת לפי הפניההפונקציה new()איסוף אשפה ב-Goסיכום - בונה רשימה מקושרת6פולימורפיזם ב-Go
פולימורפיזם באמצעות ממשקיםטיפוס ברווז ב-Goכללי התאמה לממשקאוספים פולימורפייםהזרקת תלויותסיכום - מעבד תשלומים9מקביליות ו-OOP
יסודות GoroutinesChannels ותקשורתChannel עם חוצץ לעומת ללא חוצץפקודת Selectsync.Mutex ו-sync.RWMutexsync.WaitGroupתכנון Struct בטוח לשימוש במקבילסיכום - מאגר עובדים12מושגים מתקדמים בתכנות מונחה עצמים
דפוס האפשרויות הפונקציונליותדפוס Builder ב-Goשרשור מתודותכינויי טיפוסים לעומת הגדרותיסודות Reflectionסקירה כללית של יצירת קודתרגלו בעצמכם: קומפיילר Go אונליין