परिचय: Generics क्या हैं और वे Go में क्यों आए
लंबे समय तक, Go समुदाय ने जेनेरिक्स (सामान्यीकृत प्रकार) के बिना काम चलाया। डेवलपर्स interface{} और मैन्युअल टाइप कास्टिंग का उपयोग करते थे, जिससे कोड बोझिल हो जाता था और रनटाइम पर त्रुटियाँ होती थीं। Go 1.18 (फरवरी 2022) के रिलीज़ के साथ, भाषा में आधिकारिक रूप से जेनेरिक्स जोड़े गए — यह सबसे प्रतीक्षित सुविधाओं में से एक थी।
Generics (या पैरामीट्रिक पॉलीमॉर्फिज़्म) आपको ऐसे फ़ंक्शन और डेटा संरचनाएँ लिखने की अनुमति देते हैं जो किसी भी प्रकार के साथ काम करते हैं, साथ ही कंपाइलेशन चरण पर सख्त टाइपिंग बनाए रखते हैं। इसका मतलब है कि आप एक एल्गोरिदम (जैसे, सॉर्टिंग या सर्च) लिख सकते हैं और इसे int, string, कस्टम स्ट्रक्चर के लिए उपयोग कर सकते हैं — बिना कोड डुप्लिकेशन और बिना टाइप सुरक्षा खोए।
इस लेख में, हम समझेंगे कि Go में जेनेरिक्स क्यों ज़रूरी हैं, उनका सही उपयोग कैसे करें, और किन संभावित समस्याओं पर ध्यान देना चाहिए।
मुख्य भाग: Go में Generics कैसे काम करते हैं
1. प्रकार पैरामीटर का सिंटैक्स
Go में जेनेरिक्स का मूल सिंटैक्स इस प्रकार है: फ़ंक्शन या प्रकार के नाम के बाद वर्गाकार कोष्ठक में प्रकार पैरामीटर निर्दिष्ट किए जाते हैं। आइए एक सरल उदाहरण देखें — एक फ़ंक्शन जो पास किए गए मान को लौटाता है (identity का एनालॉग):
package main
import "fmt"
// सामान्यीकृत फ़ंक्शन: T — प्रकार पैरामीटरfunc Print[T any](value T) { fmt.Println(value)}
func main() { Print[int](42) // स्पष्ट प्रकार निर्देश Print[string]("Go") // स्पष्ट प्रकार निर्देश Print("Go 1.18") // अंतर्निहित प्रकार अनुमान (type inference)}कीवर्ड any interface{} का उपनाम है। इसका मतलब है कि फ़ंक्शन किसी भी प्रकार का मान स्वीकार करता है। हालाँकि, जेनेरिक्स की असली शक्ति बाधाओं (constraints) के उपयोग से सामने आती है।
2. बाधाएँ (constraints) और इंटरफ़ेस
बाधाएँ आपको यह निर्दिष्ट करने की अनुमति देती हैं कि प्रकार पैरामीटर पर कौन से ऑपरेशन किए जा सकते हैं। उदाहरण के लिए, दो संख्याओं को जोड़ने के लिए, यह सुनिश्चित करना होगा कि प्रकार +, -, * आदि ऑपरेटरों का समर्थन करता है। Go में, इसके लिए golang.org/x/exp/constraints पैकेज से विशेष इंटरफ़ेस या कस्टम इंटरफ़ेस का उपयोग किया जाता है:
package main
import ( "fmt" "golang.org/x/exp/constraints")
// बाधा: T को तुलना का समर्थन करना चाहिएfunc Max[T constraints.Ordered](a, b T) T { if a > b { return a } return b}
func main() { fmt.Println(Max(10, 20)) // 20 fmt.Println(Max("apple", "banana")) // banana // fmt.Println(Max([]int{1}, []int{2})) // कंपाइलेशन त्रुटि: स्लाइस क्रमबद्ध नहीं हैं}अंतर्निहित इंटरफ़ेस constraints.Ordered में वे प्रकार शामिल हैं जो <, <=, >, >= ऑपरेटरों का समर्थन करते हैं: सभी संख्यात्मक प्रकार और string।
आप अपनी खुद की बाधाएँ भी बना सकते हैं:
// कस्टम बाधा: प्रकार में String() विधि होनी चाहिएtype Stringer interface { String() string}
func Describe[T Stringer](v T) string { return "Value: " + v.String()}3. सामान्यीकृत संरचनाएँ और विधियाँ
Go में जेनेरिक्स न केवल फ़ंक्शन के साथ, बल्कि कस्टम प्रकारों के साथ भी काम करते हैं। आइए एक क्लासिक उदाहरण देखें — एक सामान्यीकृत स्टैक:
package main
import "fmt"
// सामान्यीकृत संरचना Stacktype Stack[T any] struct { items []T}
// Push स्टैक में एक तत्व जोड़ता हैfunc (s *Stack[T]) Push(item T) { s.items = append(s.items, item)}
// Pop स्टैक से एक तत्व निकालता हैfunc (s *Stack[T]) Pop() (T, bool) { if len(s.items) == 0 { var zero T return zero, false } last := s.items[len(s.items)-1] s.items = s.items[:len(s.items)-1] return last, true}
func main()