في Go، map نوع بيانات مدمج يمثّل جدول تجزئة.
في لغات برمجة أخرى، ربما تعرف map باسم dict أو المصفوفة الترابطية أو مخزن مفتاح/قيمة.
إذا لم تكن على دراية بهذا المفهوم، فيمكنك أن تتخيل map كقاموس، كل كلمة فيه هي key والتعريف هو element الخاص بالـ map.
قبل أن نبدأ، أود أن أوجّهك إلى مواصفات Go حول map ومدونة Go حول map للتعمق أكثر في
map.
من الناحية التركيبية، يبدو map هكذا:
map[KeyType]ElementType
يجب أن يكون KeyType أي نوع قابل للمقارنة، بينما يمكن أن يكون ElementType أي نوع صالح في Go، ما يعني أنك تستطيع تخزين أي شيء من متغير أولي إلى شريحة.
من المهم أن تتذكر أن map في Go غير مرتّبة، فإذا حاولت المرور بحلقة على map وطباعة العنصر، فقد تفاجئك رؤية عناصرك مطبوعة بترتيب عشوائي (جرّب ذلك إن أردت).
من المهم أيضًا أن تعرف أن كل مفتاح فريد، أي أن إسناد المفتاح نفسه مرتين سيستبدل قيمة المفتاح المقابل.
map نوع مرجعي، وهذا يعني أنك إذا مرّرته هنا وهناك، فلن تنسخ Go الـ map كاملة.
ما ستفعله Go بدلًا من ذلك هو نسخ مؤشر الـ map، وهذا يجعل تمرير الـ map إلى دالة أو متغير غير مكلف.
قيمة الـ map غير المهيأة هي nil.
يمكنك تعريف map كما يلي (ونسمي هذه أيضًا خريطة nil):
var foo map[string]int
لتهيئة map، يمكنك أن تفعل:
// With map literal
foo := map[string]int{}
أو
// or with make function
foo := make(map[string]int)
الخريطة
nilمختلفة عن الخريطة المهيأة، والكتابة في خريطةnilتسبب خطأً وقت التشغيلpanic: assignment to entry in nil mapلذلك من المهم تهيئة الـ
mapقبل استخدامها
إليك بعض العمليات التي يمكنك إجراؤها على map
// Add a value in a map with the `=` operator:
foo["bar"] = 42
// Here we update the element of `bar`
foo["bar"] = 73
// To retrieve a map value, you can use
baz := foo["bar"]
// To delete an item from a map, you can use
delete(foo, "bar")
إذا حاولت استرداد قيمة مفتاح غير موجود في الـ map، فستُرجع القيمة الصفرية لنوع القيمة.
قد يربكك هذا، خصوصًا إذا كانت القيمة الافتراضية لنوع ElementType لديك (مثلًا، 0 لعدد صحيح) قيمة صالحة.
للتحقق من وجود مفتاح في الـ map، يمكنك استخدام
value, exists := foo["baz"]
// If the key "baz" does not exist,
// value: 0; exists: false
كما رأينا سابقًا، معرفة ما إذا كانت الـ map مهيأة أم لا أمر سهل، يمكننا ببساطة مقارنتها بـ nil، لكن ماذا عن المقارنة بين map وأخرى؟ حسنًا، بما أن map ليست قابلة للمقارنة، لا يمكننا استخدام عامل ==، لكن حزمة reflect لديها ما ينقذنا، وهو DeepEqual، ويمكننا استخدامه هكذا
import "reflect"
// ....
equal := reflect.DeepEqual(map[string]int{}, map[string]int{})
fmt.Println(equal)
// Output: true
لكن انتظر، إذا لم تكن map قابلة للمقارنة، فلماذا نستطيع مقارنتها بـ nil؟ حسنًا، لقد وضعت المواصفة استثناءً لهذا، انظر مواصفات المقارنة
النقطة الأخيرة: إذا حاولت الكتابة في map من عدة goroutines، فسيؤدي ذلك إلى تشغيل كاشف التسابق، انظر وثائق Go ومدونة Go.
وبدلًا من ذلك، يمكنك استخدام sync.Map أو atomic أو mutex للالتفاف على هذه المشكلة.