"मेरा Set कहाँ है?" — Go डेवलपर की आत्मा की पुकार
\n\nयदि आप Python, JavaScript या Java से Go में आए हैं, तो देर-सबेर आप यह प्रश्न पूछेंगे: "आखिर मेरा प्रिय Set कहाँ है?" — और यह सामान्य है। Stack Overflow पर विषय "Golang why don't we have a set datastructure" ने हजारों व्यूज़ और दर्जनों गर्म चर्चाएँ एकत्र की हैं। डेवलपर्स अद्वितीय तत्वों वाले सुविधाजनक सेट के आदी हैं, जबकि Go केवल arrays, slices और maps प्रदान करता है। इस लेख में हम Go के निर्माताओं के दर्शन को समझेंगे, Set का अनुकरण करना सीखेंगे और अपना स्वयं का न्यूनतम कार्यान्वयन भी लिखेंगे।
Go के निर्माताओं ने मानक लाइब्रेरी में Set क्यों नहीं जोड़ा?
\n\nइसका उत्तर भाषा के न्यूनतमवाद और व्यावहारिकता में छिपा है। Go टीम (रॉब पाइक, केन थॉम्पसन, रॉबर्ट ग्रिसेमर) ने सिद्धांत का पालन किया: "यदि कुछ एक भाषा निर्माण से किया जा सकता है, तो संस्थाओं का प्रसार न करें।" Go में map केवल एक शब्दकोश नहीं है, बल्कि एक सार्वभौमिक कंटेनर है। यह पहले से ही कुंजियों की विशिष्टता का समर्थन करता है, जो सेट का मुख्य गुण है।
दर्शन: "कम जादू - अधिक स्पष्टता"
\n\nPython के विपरीत, जहाँ set अपने स्वयं के तरीकों (.add(), .union()) के साथ एक अलग प्रकार है, Go में भाषा को जटिल न करने का निर्णय लिया गया। एक अलग संरचना क्यों लिखें जब map[T]struct{} वही काम करता है? यह मानक लाइब्रेरी में जगह बचाता है और शुरुआती लोगों के लिए प्रवेश की बाधा को कम करता है। मुख्य बात है map को set के रूप में सही ढंग से उपयोग करना सीखना।
Go में Set का अनुकरण कैसे करें: तीन कार्यशील दृष्टिकोण
\n\nआइए अभ्यास की ओर बढ़ते हैं। यहाँ बताया गया है कि केवल Go के मानक साधनों का उपयोग करके सेट को कैसे कार्यान्वित किया जा सकता है।
\n\n1. सबसे लोकप्रिय: map[type]struct{}
\n\nयह Go समुदाय में मानक दृष्टिकोण है। struct{} क्यों? क्योंकि खाली संरचना मेमोरी (0 बाइट) नहीं लेती है — तत्व के "अस्तित्व" के चिह्न के लिए आदर्श।
package main\n\nimport "fmt"\n\nfunc main() {\n // पूर्णांकों का एक सेट बनाएँ\n set := make(map[int]struct{})\n\n // तत्व जोड़ें\n set[1] = struct{}{}\n set[2] = struct{}{}\n set[3] = struct{}{}\n set[1] = struct{}{} // डुप्लिकेट को अनदेखा किया जाता है\n\n // अस्तित्व की जाँच\n if _, exists := set[2]; exists {\n fmt.Println("2 सेट में है")\n }\n\n // हटाना\n delete(set, 3)\n\n // पुनरावृत्ति\n for key := range set {\n fmt.Println(key)\n }\n}\n\nलाभ: मानों के लिए शून्य मेमोरी आवंटन, सरलता। नुकसान: कोई .Add() या .Contains() विधियाँ नहीं हैं — सब कुछ map सिंटैक्स के माध्यम से किया जाता है।
2. विधियों के साथ स्वयं का प्रकार
\n\nयदि आपको एक स्वच्छ API चाहिए, तो map को एक संरचना में लपेटें:
\n\npackage main\n\nimport "fmt"\n\n// Set — generic सेट (Go 1.18+)\ntype Set[T comparable] struct {\n items map[T]struct{}\n}\n\n// NewSet एक नया Set बनाता है\nfunc NewSet[T comparable]() *Set[T] {\n return &Set[T]{items: make(map[T]struct{})}\n}\n\n// Add एक तत्व जोड़ता है\nfunc (s *Set[T]) Add(item T) {\n s.items[item] = struct{}{}\n}\n\n// Contains उपस्थिति की जाँच करता है\nfunc (s *Set[T]) Contains(item T) bool {\n _, ok := s.items[item]\n return ok\n}\n\n// Size आकार लौटाता है\nfunc (s *Set[T]) Size() int {\n return len(s.items)\n}\n\nfunc main() {\n intSet := NewSet[int]()\n intSet.Add(10)\n intSet.Add(20)\n fmt.Println(intSet.Contains(10)) // true\n fmt.Println(intSet.Size()) // 2\n}\n\nयह पहले से ही Go में एक पूर्ण set datastructure जैसा दिखता है। जेनेरिक (generics) संस्करण 1.18 में दिखाई दिए, इसलिए कोड आधुनिक परियोजनाओं पर काम करता है।
\n\n3. struct{} के बजाय bool का उपयोग
\n\nकुछ लोग map[T]bool का उपयोग करते हैं, लेकिन यह मान पर 1 बाइट खर्च करता है। अधिकांश मामलों में अंतर नगण्य है, लेकिन यदि आप उच्च-लोड सेवा लिख रहे हैं — तो struct{} पर टिके रहना बेहतर है।