الـ Pointers كقيم في الـ Maps
جزء من قسم Logic & Flow في رحلة GO على Coddy — الدرس 27 من 68.
بينما يعد تخزين الـ structs مباشرة في الـ maps أمراً مفيداً، فإن تخزين المؤشرات (pointers) إلى الـ structs يفتح إمكانية قوية: القدرة على تعديل بيانات الـ struct الأصلية مباشرة من خلال الـ map. هذا النهج ضروري عندما تحتاج إلى تحديث بياناتك بعد تخزينها.
عندما تقوم بتخزين مؤشر (pointer) إلى هيكل (struct) كقيمة في خريطة (map)، فإنك تقوم بتخزين عنوان الذاكرة للهيكل، وليس نسخة منه. إليك كيفية التصريح عن مثل هذه الخريطة والتعامل معها:
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},
}تتضح الميزة الأساسية عندما تحتاج إلى تعديل البيانات. نظرًا لأنك تتعامل مع المؤشرات (pointers)، فإن التغييرات التي يتم إجراؤها من خلال الخريطة (map) تؤثر على الهيكل (struct) الأصلي:
// تحديث سعر الكمبيوتر المحمول مباشرة من خلال الخريطة
products["laptop"].Price = 899.99
fmt.Println(products["laptop"].Price) // يطبع: 899.99هذا النمط ذو قيمة خاصة في التطبيقات التي تحتاج فيها إلى تحديث البيانات المخزنة بشكل متكرر، مثل أنظمة المخزون، أو ملفات تعريف المستخدمين، أو أي سيناريو تعمل فيه الخريطة (map) كمخزن بياناتك الأساسي وتحتاج فيه التعديلات إلى الاستمرار.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
التحدي
سهلقم ببناء نظام بسيط لإدارة المخزون يوضح قوة استخدام المؤشرات (pointers) لهياكل البيانات (structs) كقيم في الخرائط (maps). يوضح هذا التحدي كيف تمكن الخرائط القائمة على المؤشرات من التعديل المباشر للبيانات المخزنة، مما يجعل نظام المخزون الخاص بك فعالاً وسريع الاستجابة للتحديثات.
ستتلقى ثلاثة مدخلات:
- سلسلة نصية تمثل عدد المنتجات (مثلاً،
"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) - كمية المخزون للمنتج
- إنشاء خريطة (map) حيث تكون المفاتيح هي أسماء المنتجات (strings) والقيم هي مؤشرات (pointers) لهياكل
Product - تحليل بيانات المنتج من المدخل الثاني:
- تقسيم المدخل بواسطة الفواصل للحصول على إدخالات المنتجات الفردية
- لكل إدخال، قم بالتقسيم بواسطة النقطتين الرأسيتين لفصل الاسم والسعر والكمية
- تحويل سلسلة السعر النصية إلى float64 وسلسلة الكمية النصية إلى عدد صحيح (integer)
- إنشاء هيكل
Productوتخزين مؤشر له في الخريطة
- عرض المخزون الأولي مع العنوان
"Initial Inventory:" - إظهار كل منتج بالتنسيق التالي:
"[name]: $[price] (Stock: [quantity])" - تحليل وتطبيق عمليات التحديث من المدخل الثالث:
- تقسيم المدخل بواسطة الفواصل للحصول على العمليات الفردية
- لكل عملية، قم بالتقسيم بواسطة النقطتين الرأسيتين للحصول على نوع العملية، واسم المنتج، والقيمة الجديدة
- تحديث الحقل المناسب مباشرة من خلال مؤشر الخريطة
- طباعة كل تحديث بالتنسيق التالي:
"Updated [product]: [field] changed to [new_value]"
- عرض المخزون المحدث مع العنوان
"Updated Inventory:" - إظهار كل منتج مرة أخرى بنفس تنسيق العرض الأولي
- حساب وعرض القيمة الإجمالية للمخزون:
"Total Inventory Value: $[total_value]"
استخدم حزمة strconv لتحويل سلاسل السعر والكمية النصية إلى أنواعها الرقمية المقابلة. قم بتنسيق جميع الأسعار إلى منزلتين عشريتين عند العرض. يوضح هذا التحدي كيف يسمح لك تخزين المؤشرات في الخرائط بتعديل بيانات الهيكل الأصلية مباشرة، مما يجعل تحديثات المخزون فورية ومستمرة دون الحاجة إلى إعادة تعيين القيم في الخريطة.
ورقة مرجعية
يمكن للخرائط (Maps) تخزين مؤشرات إلى الهياكل (structs)، مما يسمح بالتعديل المباشر لبيانات الهيكل الأصلي من خلال الخريطة:
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هذا النمط مفيد للتطبيقات التي تتطلب تحديثات متكررة للبيانات، مثل أنظمة المخزون أو ملفات تعريف المستخدمين، حيث تعمل الخريطة كمخزن بيانات أساسي.
جرّب بنفسك
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: قم بتعريف هيكل المنتج (Product struct) هنا
// TODO: قم بإنشاء خريطة (map) لتخزين مؤشرات المنتجات
// TODO: قم بإنشاء شريحة (slice) للحفاظ على ترتيب المنتجات (لضمان مخرجات متسقة)
// TODO: قم بتحليل بيانات المنتج وملء الخريطة
// تذكر أن تقوم بـ:
// - تقسيم productDataStr بواسطة الفواصل للحصول على المدخلات الفردية
// - لكل مدخل، قم بالتقسيم بواسطة النقطتين الرأسيتين للحصول على الاسم والسعر والكمية
// - تحويل سلاسل السعر والكمية إلى الأنواع المناسبة
// - تخزين مؤشر لهيكل المنتج في الخريطة
// - إضافة اسم المنتج إلى شريحة الترتيب
// TODO: عرض المخزون الأولي
// استخدم شريحة الترتيب للتكرار عبر المنتجات بشكل متسق
// التنسيق: "[name]: $[price] (Stock: [quantity])"
// TODO: تحليل وتطبيق عمليات التحديث
// تذكر أن تقوم بـ:
// - تقسيم operationsStr بواسطة الفواصل للحصول على العمليات الفردية
// - لكل عملية، قم بالتقسيم بواسطة النقطتين الرأسيتين للحصول على النوع والاسم والقيمة
// - تحديث الحقل المناسب مباشرة من خلال مؤشر الخريطة
// - طباعة رسالة تحديث لكل عملية
// TODO: عرض المخزون المحدث
// مرة أخرى، استخدم شريحة الترتيب للحصول على مخرجات متسقة
// احسب القيمة الإجمالية أثناء العرض
// TODO: حساب وعرض القيمة الإجمالية للمخزون
// التنسيق: "Total Inventory Value: $[total_value]"
}يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Logic & Flow
1تدفق التحكم المتقدم
جملة Switch مع `fallthrough`الخروج من الحلقات المتداخلةالاستمرار في حلقة محددةجملة `goto`ملخص - التحكم المتقدم في الحلقات2الـ Structs والميثودز (Methods)
تعريف الـ Methods على الـ Structsالـ Value Receiversالـ Pointer Receiversاختيار الـ Receiversالـ Methods مقابل الـ Functionsملخص - سلوك الـ Struct5تعمق في الـ Maps
Maps من نوع Structsالـ Pointers كقيم في الـ Mapsالتحقق من الـ Nil Mapsمقارنة الـ Mapsمراجعة - عداد تكرار الكلمات3الواجهات (الأساسيات)
ما هي الواجهة؟تعريف الواجهةتطبيق الواجهةاستخدام أنواع الواجهاتالواجهة الفارغةتأكيدات النوع (Type Assertions)تبديل النوع (Type Switch)ملخص - الأشكال والسلوكيات