परिचय: Stack Overflow का वह सवाल
\n\nअगर आपने कभी "Declare a constant array in Go" गूगल किया है, तो आपने शायद Stack Overflow पर वही थ्रेड देखा होगा जिसके हज़ारों व्यूज़ हैं। और हाँ, आप अकेले नहीं हैं जो इससे कन्फ्यूज़ हुए हैं। Go में सीधे const arr = [...]int{1, 2, 3} लिखना संभव नहीं है — कंपाइलर आपको विनम्रता से "नहीं" कहेगा।
ऐसा क्यों? और अगर हमें अपरिवर्तनीय डेटा की सूची चाहिए तो क्या करें? इस लेख में हम Go में कॉन्स्टेंट की प्रकृति को समझेंगे, जानेंगे कि ऐरे कॉन्स्टेंट क्यों नहीं हो सकते, और सबसे अच्छे विकल्प खोजेंगे। स्पॉयलर: एक समाधान है, और यह आपकी सोच से भी ज़्यादा खूबसूरत है।
\n\nGo कॉन्स्टेंट ऐरे की अनुमति क्यों नहीं देता?
\n\nइसे समझने के लिए, भाषा के अंदरूनी हिस्से में झाँकना होगा। Go में कॉन्स्टेंट अपरिवर्तनीय मान होते हैं जो कंपाइल टाइम पर गणना किए जाते हैं। वे सख्ती से टाइप किए गए होने चाहिए और प्रोग्राम चलने से पहले ज्ञात होने चाहिए। ऐरे, हालांकि, कंपाउंड डेटा टाइप हैं जो मेमोरी लेते हैं और बदले जा सकते हैं।
\n\nयहाँ एक सरल उदाहरण है जो कंपाइल नहीं होगा:
\n\npackage main\n\nconst arr = [3]int{1, 2, 3} // त्रुटि: const initializer [3]int{1, 2, 3} is not a constant\n\nfunc main() {\n fmt.Println(arr)\n}\n\nकंपाइलर कहता है: "अरे, यह कॉन्स्टेंट नहीं है!" और वह सही है। भले ही ऐरे को const घोषित किया गया हो, Go गारंटी नहीं देता कि इसकी सामग्री पॉइंटर्स या स्लाइस के माध्यम से नहीं बदलेगी। इसलिए भाषा के डेवलपर्स ने फैसला किया: कोई कॉन्स्टेंट ऐरे नहीं।
लेकिन परेशान न हों। इस सीमा को पार करने के कम से कम तीन तरीके हैं, और प्रत्येक के अपने फायदे हैं।
\n\nतरीका 1: वेरिएबल का उपयोग करें और "न छुएं" का कमेंट लगाएं
\n\nसबसे आसान और सीधा तरीका — बस एक वेरिएबल घोषित करें और उम्मीद करें कि कोई इसे नहीं बदलेगा। लेकिन हम गंभीर डेवलपर हैं, है ना?
\n\npackage main\n\nimport "fmt"\n\n// arr - कॉन्स्टेंट ऐरे। कृपया इसे न बदलें।\nvar arr = [3]int{1, 2, 3}\n\nfunc main() {\n fmt.Println(arr)\n // arr[0] = 100 // इसे अनकमेंट करें — और सब कुछ टूट जाएगा\n}\n\nनुकसान स्पष्ट हैं: यह असली कॉन्स्टेंट नहीं है। कोई भी असाइनमेंट के ज़रिए ऐरे को बदल सकता है। लेकिन त्वरित प्रोटोटाइप या छोटे प्रोजेक्ट्स के लिए — यह चल जाएगा।
\n\nतरीका 2: गेटर फंक्शन (सही तरीका)
\n\nयह तरीका प्रोडक्शन कोड में उपयोग किया जाता है। हम ऐरे को फंक्शन के अंदर छिपाते हैं और इसकी कॉपी लौटाते हैं। इस तरह कोई भी मूल को नहीं बदल सकता।
\n\npackage main\n\nimport "fmt"\n\n// getColors रंगों के ऐरे की कॉपी लौटाता है।\n// ऐरे बाहरी बदलावों से सुरक्षित है।\nfunc getColors() [3]string {\n return [3]string{"Red", "Green", "Blue"}\n}\n\nfunc main() {\n colors := getColors()\n fmt.Println(colors)\n // colors[0] = "Yellow" // यह कॉपी को बदलेगा, मूल को नहीं\n}\n\nयह अच्छा क्यों है? क्योंकि:
\n- \n
- ऐरे को बाहर से नहीं बदला जा सकता — फंक्शन कॉपी लौटाता है। \n
- कोड पढ़ने और समझने में आसान है। \n
- टेस्ट और मेंटेन करना आसान है। \n
लेकिन एक बात है: फंक्शन का हर कॉल एक नई कॉपी बनाता है। अगर ऐरे बड़ा है (जैसे, 1000 एलिमेंट), तो यह महंगा हो सकता है। ऐसे में अगला तरीका उपयोग करें।
\n\nतरीका 3: प्राइवेट एक्सेस के साथ पैकेज वेरिएबल
\n\nअगर आप एक पैकेज लिख रहे हैं और ऐरे को बदलावों से बचाना चाहते हैं, तो इसे नॉन-एक्सपोर्टेड (छोटे अक्षर से) बनाएं और फंक्शन के ज़रिए एक्सेस दें।
\n\npackage constants\n\n// ऐरे केवल पैकेज के अंदर उपलब्ध है\nvar defaultPorts = [5]int{80, 443, 8080, 3000, 5000}\n\n// GetDefaultPorts पोर्ट्स के ऐरे की कॉपी लौटाता है।\nfunc GetDefaultPorts() [5]int {\n return defaultPorts\n}\n\nअब आपके पैकेज के उपयोगकर्ता केवल डेटा पढ़ सकते हैं, बदल नहीं सकते। लाइब्रेरी के लिए एकदम सही।
\n\nतरीका 4: कॉन्स्टेंट सेट के लिए iota का उपयोग
\n\nक्या होगा अगर आपको मानों की नहीं, बल्कि उनके इंडेक्स की ज़रूरत है? उदाहरण के लिए...