מצביעים כערכים במפה
חלק מהיחידה לוגיקה וזרימת התוכנית במסלול ה-GO של Coddy. שיעור 27 מתוך 68.
אף ששמירת מבנים ישירות במפות היא שימושית, שמירת מצביעים למבנים פותחת אפשרות רבת־עוצמה: לשנות את נתוני המבנה המקורי ישירות דרך המפה. גישה זו חיונית כשצריך לעדכן את הנתונים לאחר ששמרת אותם.
כשמאחסנים מצביע למבנה כערך במפה, מאחסנים את כתובת הזיכרון של המבנה, ולא עותק שלו. כך מצהירים על מפה כזו ומשתמשים בה:
type Product struct {
Price float64
Quantity int
}
products := map[string]*Product{
"laptop": &Product{Price: 999.99, Quantity: 5},
"mouse": &Product{Price: 25.50, Quantity: 20},
}היתרון המרכזי מתברר כשצריך לשנות את הנתונים. מכיוון שעובדים עם מצביעים, שינויים שנעשים דרך המפה משפיעים על המבנה המקורי:
// עדכנו את מחיר המחשב הנייד ישירות דרך המפה
products["laptop"].Price = 899.99
fmt.Println(products["laptop"].Price) // מדפיס: 899.99התבנית הזאת שימושית במיוחד ביישומים שבהם צריך לעדכן לעיתים קרובות נתונים מאוחסנים, כמו מערכות מלאי, פרופילי משתמשים או כל תרחיש שבו המפה משמשת כמאגר הנתונים הראשי שלך והשינויים צריכים להישמר.
אתגר
קלבנו מערכת פשוטה לניהול מלאי שמדגימה את העוצמה של שימוש במצביעים למבנים כערכים במפה. האתגר הזה מראה כיצד מפות המבוססות על מצביעים מאפשרות לשנות ישירות את הנתונים המאוחסנים, וכך להפוך את מערכת המלאי שלכם ליעילה ומגיבה לעדכונים.
תקבלו שלוש קלטים:
- מחרוזת שמייצגת את מספר המוצרים (למשל,
"4") - מחרוזת שמכילה נתוני מוצרים בפורמט:
"name1:price1:quantity1,name2:price2:quantity2,name3:price3:quantity3"(למשל,"laptop:999.99:5,mouse:25.50:20,keyboard:75.00:15,monitor:299.99:8") - מחרוזת שמכילה פעולות עדכון בפורמט:
"operation1:product1:value1,operation2:product2:value2", כאשר הפעולות הן"price"או"quantity"(למשל,"price:laptop:899.99,quantity:mouse:25,price:keyboard:65.00")
המשימה שלכם היא:
- להגדיר מבנה
Productעם השדות הבאים:Price(float64) - מחיר המוצרQuantity(int) - כמות המוצר במלאי
- ליצור מפה שבה המפתחות הם שמות המוצרים (מחרוזות) והערכים הם מצביעים למבני
Product - לנתח את נתוני המוצרים מהקלט השני:
- לפצל את הקלט לפי פסיקים כדי לקבל רשומות של מוצרים בודדים
- עבור כל רשומה, לפצל לפי נקודתיים כדי להפריד בין השם, המחיר והכמות
- להמיר את מחרוזת המחיר ל-float64 ואת מחרוזת הכמות למספר שלם
- ליצור מבנה
Productולאחסן מצביע אליו במפה
- לשמור את שמות המוצרים בפרוסה נפרדת במהלך הניתוח, לפי הסדר שבו הם מופיעים בקלט. מעבר על מפה ב-Go מבקר במפתחות בסדר אקראי, ולכן הפרוסה היא זו ששומרת על הסדר המקורי של כל הרשימות.
- להציג את המלאי הראשוני עם הכותרת
"Initial Inventory:" - להציג כל מוצר בפורמט:
"[name]: $[price] (Stock: [quantity])" - לנתח ולהחיל את פעולות העדכון מהקלט השלישי:
- לפצל את הקלט לפי פסיקים כדי לקבל פעולות בודדות
- עבור כל פעולה, לפצל לפי נקודתיים כדי לקבל את סוג הפעולה, שם המוצר והערך החדש
- לעדכן את השדה המתאים ישירות דרך המצביע שבמפה
- להדפיס כל עדכון בפורמט:
"Updated [product]: [field] changed to [new_value]"
- להציג את המלאי המעודכן עם הכותרת
"Updated Inventory:" - להציג שוב כל מוצר באותו פורמט כמו בתצוגה הראשונית
- לחשב ולהציג את הערך הכולל של המלאי:
"Total Inventory Value: $[total_value]"
השתמשו בחבילה strconv כדי להמיר את מחרוזות המחיר והכמות לסוגים המספריים המתאימים. הציגו את כל המחירים עם 2 ספרות אחרי הנקודה העשרונית. האתגר הזה מדגים כיצד אחסון מצביעים במפות מאפשר לשנות ישירות את נתוני המבנה המקורי, וכך לעדכן את המלאי באופן מיידי ומתמשך, בלי צורך להקצות מחדש ערכים במפה.
נסו בעצמכם
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
// קראו את הקלט
var numProductsStr string
var productDataStr string
var operationsStr string
fmt.Scanln(&numProductsStr)
fmt.Scanln(&productDataStr)
fmt.Scanln(&operationsStr)
// TODO: הגדירו כאן את ה-struct Product
// TODO: צרו map לאחסון מצביעים למוצרים
// TODO: צרו slice לשמירה על סדר המוצרים (כדי להבטיח פלט עקבי)
// TODO: נתחו את נתוני המוצרים ומלאו את ה-map
// זכרו:
// - פצלו את productDataStr לפי פסיקים כדי לקבל רשומות נפרדות
// - עבור כל רשומה, פצלו לפי נקודתיים כדי לקבל שם, מחיר וכמות
// - המירו את המחרוזות של המחיר והכמות לטיפוסים המתאימים
// - אחסנו מצביע ל-struct Product ב-map
// - הוסיפו את שם המוצר ל-slice של הסדר
// TODO: הציגו את המלאי ההתחלתי
// השתמשו ב-slice של הסדר כדי לעבור על המוצרים באופן עקבי
// פורמט: "[name]: $[price] (Stock: [quantity])"
// TODO: נתחו והחילו את פעולות העדכון
// זכרו:
// - פצלו את operationsStr לפי פסיקים כדי לקבל פעולות נפרדות
// - לכל פעולה, פצלו לפי נקודתיים כדי לקבל סוג, שם וערך
// - עדכנו את השדה המתאים ישירות דרך המצביע שב-map
// - הדפיסו הודעת עדכון לכל פעולה
// TODO: הציגו את המלאי המעודכן
// שוב, השתמשו ב-slice של הסדר כדי להפיק פלט עקבי
// חשבו את הערך הכולל בזמן ההצגה
// TODO: חשבו והציגו את הערך הכולל של המלאי
// פורמט: "Total Inventory Value: $[total_value]"
}השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה לוגיקה וזרימת התוכנית
1בקרת זרימה מתקדמת
switch עם `fallthrough`יציאה מלולאות מקוננותהמשך לולאה מסוימתהצהרת `goto`סיכום – שליטה מתקדמת בלולאות4פרויקט: רשימת משימות פשוטה
הגדרת הפרויקטהוספת משימה2מבנים ושיטות
הגדרת שיטות במבניםמקבלי ערךמקבלי מצביעבחירת מקבליםשיטות לעומת פונקציותסיכום — התנהגות המבנים5מפות לעומק
מפות של Structsמצביעים כערכים במפהבדיקה אם מפות הן nilהשוואת מפותסיכום - מונה תדירות מילים8פרויקט: ניהול מלאי פשוט
סקירת הפרויקטבדיקת המלאיתרגלו בעצמכם: קומפיילר Go אונליין