Make या New? Go डेवलपर का शाश्वत प्रश्न
\n\nआप एक सप्ताह या एक वर्ष से Go में कोड लिख रहे हैं, लेकिन फिर भी कभी-कभी make() या new() चुनने से पहले एक पल के लिए रुक जाते हैं? यह सामान्य है। Stack Overflow पर "Why would I make() or new()?" प्रश्न ने दसियों हज़ार बार देखा गया है, और यह 2025 में भी प्रासंगिक बना हुआ है। क्यों? क्योंकि स्पष्ट सादगी के पीछे Go में मेमोरी प्रबंधन के दर्शन में एक मौलिक अंतर छिपा है।
आइए एक बार और हमेशा के लिए समझ लें कि क्या है, ताकि आपको फिर से अनुमान न लगाना पड़े। हम बुनियादी बातों से लेकर वास्तविक मामलों तक जाएंगे, नुकसानों को उजागर करेंगे और दैनिक कार्य के लिए एक चेकलिस्ट देंगे। चलिए शुरू करते हैं!
\n\nसंक्षिप्त उत्तर (उन लोगों के लिए जो जल्दी में हैं)
\n\nयदि आपको स्लाइस (slice), मैप (map) या चैनल (channel) के लिए मेमोरी आवंटित करने की आवश्यकता है — तो make() का उपयोग करें। अन्य सभी मामलों में — new() या लिटरल &Type{} का उपयोग करें। लेकिन शैतान, हमेशा की तरह, विवरण में है।
new() क्या है और यह कैसे काम करता है
\n\nफ़ंक्शन new(T) — Go का एक बिल्ट-इन फ़ंक्शन है, जो प्रकार T के लिए मेमोरी आवंटित करता है, इसे शून्य करता है (zero value) और इस मेमोरी पर एक पॉइंटर लौटाता है: *T।
सीधे शब्दों में कहें: new() आपको एक खाली लेकिन मान्य ऑब्जेक्ट देता है। आपको एक पॉइंटर मिलता है, लेकिन ऑब्जेक्ट स्वयं अभी पूरी तरह से उपयोग के लिए तैयार नहीं है, यदि इसे आंतरिक संरचनाओं के आरंभीकरण की आवश्यकता है।
package main\n\nimport "fmt"\n\ntype Person struct {\n Name string\n Age int\n}\n\nfunc main() {\n p := new(Person)\n fmt.Println(p) // आउटपुट: &{ 0}\n fmt.Println(p.Name == "") // true\n}\n\n\nयहाँ new(Person) ने स्ट्रक्चर के लिए मेमोरी आवंटित की, फ़ील्ड को शून्य किया (खाली स्ट्रिंग और 0) और पॉइंटर लौटाया। सब कुछ सही है।
make() क्या है और इसकी सुपरपावर
\n\nmake() — भी एक बिल्ट-इन फ़ंक्शन है, लेकिन यह केवल तीन प्रकारों के साथ काम करता है: स्लाइस, मैप और चैनल। केवल ये क्यों? क्योंकि इन प्रकारों की एक आंतरिक संरचना (हेडर) होती है जिसे केवल शून्य करने के बजाय आरंभ करने की आवश्यकता होती है।
make() पॉइंटर नहीं लौटाता। यह आवश्यक प्रकार का एक आरंभीकृत मान लौटाता है (पॉइंटर नहीं!)।
// स्लाइस: लंबाई 5, क्षमता 10\ns := make([]int, 5, 10)\nfmt.Println(len(s), cap(s)) // 5 10\n\n// मैप: तत्वों को सम्मिलित करने के लिए तैयार\nm := make(map[string]int)\nm["key"] = 42\nfmt.Println(m) // map[key:42]\n\n// चैनल: 3 संदेशों के लिए बफ़र किया गया\nch := make(chan int, 3)\nch <- 1\nfmt.Println(<-ch) // 1\n\n\nध्यान दें: यदि आप m := new(map[string]int) लिखने का प्रयास करते हैं, तो आपको nil-मैप पर एक पॉइंटर मिलेगा। ऐसे मैप में एक तत्व सम्मिलित करने से पैनिक (panic) हो जाएगा।
new() स्लाइस, मैप और चैनल के लिए क्यों काम नहीं करता?
\n\nआइए स्लाइस के उदाहरण पर देखें। Go में स्लाइस तीन फ़ील्ड की एक संरचना है: ऐरे पर पॉइंटर, लंबाई और क्षमता। new([]int) इस संरचना के लिए मेमोरी आवंटित करेगा और इसे शून्य करेगा। पॉइंटर nil होगा, लंबाई और क्षमता 0 होगी। आपको &[] मिलेगा — एक nil-स्लाइस पर पॉइंटर। क्या यह इंडेक्स द्वारा असाइनमेंट पर टूट जाएगा? नहीं, यह क्रैश हो जाएगा।
make([]int, 3) तीन काम करता है:
- \n
- हुड के नीचे 3 तत्वों (या अधिक, यदि क्षमता निर्दिष्ट है) की एक वास्तविक ऐरे आवंटित करता है। \n
- स्लाइस हेडर (pointer, length, capacity) को आरंभ करता है। \n
- उपयोग के लिए तैयार स्लाइस लौटाता है। \n
मैप के साथ भी ऐसा ही: make(map[string]int) एक हैश टेबल बनाता है और बकेट के लिए मेमोरी आवंटित करता है। new(map[string]int) केवल nil-मैप देता है।
2025 में new() का उपयोग कब करें?
\n\nGo समुदाय में आधुनिक अभ्यास यह है: new() का उपयोग शायद ही कभी किया जाता है। अक्सर, डेवलपर पता लेने के साथ लिटरल पसंद करते हैं: &Type{}। यह अधिक पठनीय है और तुरंत फ़ील्ड सेट करने की अनुमति देता है।