יסודות הטמעת Struct
חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 35 מתוך 107.
הטמעת מבנים היא המנגנון של Go לשילוב טיפוס מבנה אחד בתוך מבנה אחר. במקום להשתמש בשם שדה, פשוט מציינים את הטיפוס, ו-Go מקדמת את השדות של המבנה המוטמע למבנה החיצוני.
הנה התחביר הבסיסי:
type Address struct {
City string
Country string
}
type Person struct {
Name string
Address // מוטמע - ללא שם שדה
}
כשמטמיעים את Address בתוך Person, אפשר לגשת ישירות לשדות המוטמעים במבנה החיצוני:
func main() {
p := Person{
Name: "Alice",
Address: Address{
City: "London",
Country: "UK",
},
}
fmt.Println(p.City) // London - גישה ישירה
fmt.Println(p.Country) // UK - גישה ישירה
fmt.Println(p.Address.City) // גם עובד
}
שימו לב כיצד p.City עובד בלי לכתוב במפורש p.Address.City. Go מקדמת אוטומטית את השדות של המבנה המוטמע, וכך הם נגישים כאילו השתייכו למבנה החיצוני. עדיין אפשר לגשת אליהם דרך שם הטיפוס המוטמע כשצריך.
זה שונה ממבנים מקוננים רגילים, שבהם תמיד צריך להשתמש בשם השדה כדי לגשת לשדות פנימיים. הטמעה יוצרת API שטוח ונוח יותר, תוך שמירה על קיבוץ לוגי של נתונים קשורים.
אתגר
קלבואו נבנה מערכת לרישום כלי רכב שמשתמשת בהטמעת struct כדי ליצור מודל נתונים נקי ומאורגן. תפרידו בין פרטי יצירת הקשר לפרטי הרכב, תוך מתן אפשרות לגשת ישירות לכל השדות באמצעות ההטמעה.
תארגנו את הקוד שלכם בשני קבצים:
vehicle.go: צרו שני structs שפועלים יחד באמצעות הטמעה:- struct בשם
ContactInfoעם השדותOwnerNameו-Phone(שניהם מחרוזות) - struct בשם
Vehicleשמטמיע אתContactInfo(ללא שם שדה) ומוסיף שדות משלו:Make,Modelו-Year
SummaryעבורVehicle, שמחזירה מחרוזת מעוצבת הכוללת את כל פרטי הרכב ופרטי יצירת הקשר.- struct בשם
main.go: קראו את פרטי הרכב והבעלים מהקלט, צרו מופע שלVehicleעםContactInfoמוטמע, והדגימו גישה לשדות המוטמעים הן ישירות והן דרך שם הטיפוס המוטמע. הדפיסו את סיכום הרכב בסוף.
הקלטים הבאים יסופקו:
- שורה 1: שם הבעלים
- שורה 2: מספר טלפון
- שורה 3: יצרן הרכב
- שורה 4: דגם הרכב
- שורה 5: שנה (מספר שלם)
המתודה Summary שלכם צריכה להחזיר מחרוזת בפורמט הבא:
[Year] [Make] [Model] - Owner: [OwnerName], Phone: [Phone]בקובץ הראשי שלכם, הדגימו קידום שדות באמצעות הדפסה של:
- שם הבעלים שניגשים אליו ישירות מתוך Vehicle (לדוגמה,
v.OwnerName) - מספר הטלפון שניגשים אליו דרך הטיפוס המוטמע (לדוגמה,
v.ContactInfo.Phone) - הסיכום המלא באמצעות המתודה
Summaryשלכם
לדוגמה, עבור Alice Smith, 555-1234, Toyota, Camry ו-2023, הפלט שלכם צריך להיות:
Alice Smith
555-1234
2023 Toyota Camry - Owner: Alice Smith, Phone: 555-1234שימו לב ששתי צורות הגישה פועלות: גישה ישירה באמצעות קידום שדות, וגישה מפורשת דרך שם הטיפוס המוטמע. כך יש לכם גמישות באופן העבודה עם נתונים מוטמעים.
נסו בעצמכם
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// קראו את שם הבעלים
ownerName, _ := reader.ReadString('\n')
ownerName = strings.TrimSpace(ownerName)
// קראו את מספר הטלפון
phone, _ := reader.ReadString('\n')
phone = strings.TrimSpace(phone)
// קראו את יצרן הרכב
make, _ := reader.ReadString('\n')
make = strings.TrimSpace(make)
// קראו את דגם הרכב
model, _ := reader.ReadString('\n')
model = strings.TrimSpace(model)
// קראו את שנת הייצור
yearStr, _ := reader.ReadString('\n')
yearStr = strings.TrimSpace(yearStr)
year, _ := strconv.Atoi(yearStr)
// TODO: צרו מופע של Vehicle עם ContactInfo מוטמע
// השתמשו בערכים שנקראו מהקלט למעלה
// TODO: הדפיסו את שם הבעלים באמצעות גישה ישירה דרך Vehicle (קידום שדות)
// דוגמה: fmt.Println(v.OwnerName)
// TODO: הדפיסו את מספר הטלפון באמצעות גישה דרך שם הטיפוס המוטמע
// דוגמה: fmt.Println(v.ContactInfo.Phone)
// TODO: הדפיסו את הסיכום המלא באמצעות המתודה Summary
// דוגמה: fmt.Println(v.Summary())
// הסירו את השורות האלה לאחר שתממשו את הפתרון
_ = ownerName
_ = phone
_ = make
_ = model
_ = year
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
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 אונליין