Go में map एक बिल्ट-इन डेटा टाइप है, जो हैश टेबल को दर्शाता है।
दूसरी प्रोग्रामिंग भाषाओं में आप मैप को dict या असोसिएटिव ऐरे या की-वैल्यू स्टोर के नाम से जानते होंगे।
अगर आप ऐसे कॉन्सेप्ट से परिचित नहीं हैं, तो आप मैप को एक डिक्शनरी की तरह समझ सकते हैं, जिसमें हर शब्द key होता है और उसकी परिभाषा उस मैप का element होती है।
शुरू करने से पहले, मैं आपका ध्यान
mapकी और गहराई में जाने के लिए मैप के लिए Go का स्पेक और मैप के लिए Go का ब्लॉग की ओर दिलाना चाहूँगा।
सिंटैक्स के हिसाब से map ऐसा दिखता है:
map[KeyType]ElementType
KeyType कोई भी तुलनीय टाइप होना चाहिए, जबकि ElementType Go में कोई भी मान्य टाइप हो सकता है। यानी आप प्रिमिटिव वेरिएबल से लेकर स्लाइस तक कुछ भी संग्रहीत कर सकते हैं।
यह याद रखना ज़रूरी है कि Go में map अक्रमित है। अगर आप किसी map पर लूप चलाकर उसके एलिमेंट प्रिंट करने की कोशिश करेंगे, तो आप खुद हैरान रह जाएँगे, क्योंकि आपके एलिमेंट किसी भी क्रम में प्रिंट होंगे (चाहें तो खुद आज़मा कर देखिए)।
यह भी जानना ज़रूरी है कि हर की अद्वितीय होती है, यानी एक ही की को दो बार असाइन करें तो उस की की पुरानी वैल्यू की जगह नई वैल्यू आ जाती है।
map एक रेफरेंस टाइप है, यानी जब आप इसे कहीं पास करते हैं, तो Go पूरा मैप कॉपी नहीं करता।
इसके बजाय Go मैप का पॉइंटर कॉपी करता है। इससे मैप को किसी फंक्शन या वेरिएबल को पास करना बहुत कम खर्चीला हो जाता है।
बिना इनिशियलाइज़ किए गए मैप की वैल्यू nil होती है।
आप मैप को इस तरह घोषित कर सकते हैं (इसे nil मैप भी कहते हैं):
var foo map[string]int
मैप को इनिशियलाइज़ करने के लिए आप यह कर सकते हैं:
// 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इसलिए मैप को इस्तेमाल करने से पहले इनिशियलाइज़ करना ज़रूरी है
मैप के साथ किए जा सकने वाले कुछ ऑपरेशन ये हैं
// 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")
अगर आप ऐसी की से जुड़ी वैल्यू निकालने की कोशिश करेंगे जो मैप में मौजूद ही नहीं है, तो आपको उस वैल्यू टाइप की शून्य वैल्यू मिलेगी।
इससे आप उलझन में पड़ सकते हैं, खासकर तब जब आपके ElementType की डिफ़ॉल्ट वैल्यू (जैसे किसी int के लिए 0) एक मान्य वैल्यू हो।
यह जाँचने के लिए कि कोई की आपके मैप में मौजूद है या नहीं, आप यह कर सकते हैं
value, exists := foo["baz"]
// If the key "baz" does not exist,
// value: 0; exists: false
जैसा हम पहले देख चुके हैं, यह पता लगाना आसान है कि कोई map इनिशियलाइज़ है या नहीं। हम उसकी तुलना सीधे nil से कर सकते हैं। लेकिन दूसरे मैप का क्या? चूँकि map तुलनीय नहीं है, हम == ऑपरेटर इस्तेमाल नहीं कर सकते। पर reflect पैकेज हमारी मदद के लिए कुछ लेकर आता है, जिसे DeepEqual कहते हैं। हम इसे ऐसे इस्तेमाल कर सकते हैं
import "reflect"
// ....
equal := reflect.DeepEqual(map[string]int{}, map[string]int{})
fmt.Println(equal)
// Output: true
लेकिन रुकिए, अगर map तुलनीय नहीं है, तो हम उसकी तुलना nil से क्यों कर पाते हैं? वास्तव में स्पेक ने इसके लिए एक अपवाद बनाया है, देखिए तुलनीय टाइप का स्पेक
अंत में, अगर आप एक ही map में कई गोरूटिन से लिखने की कोशिश करेंगे, तो रेस डिटेक्टर चालू हो जाएगा। देखिए Go Docs और The Go Blog।
इसके बजाय आप इस समस्या से बचने के लिए sync.Map या atomic या mutex इस्तेमाल कर सकते हैं।