Go में Generics: क्यों ज़रूरी हैं और कैसे उपयोग करें
Go 1.18 संस्करण के आने के साथ, भाषा में सबसे प्रतीक्षित सुविधाओं में से एक — जेनेरिक्स (सामान्यीकृत प्रोग्रामिंग) शामिल हुई। इस क्षण तक, डेवलपर्स को या तो विभिन्न डेटा प्रकारों के लिए कोड डुप्लिकेट करना पड़ता था, या खाली इंटरफ़ेस interface{} का उपयोग करके टाइप कास्टिंग करनी पड़ती थी। Generics इस समस्या को मौलिक रूप से हल करते हैं। इस लेख में, हम समझेंगे कि वे क्यों ज़रूरी हैं, व्यवहार में उनका उपयोग कैसे करें, और आपको किन खतरों का सामना करना पड़ सकता है।
जेनेरिक्स क्या हैं और Go में इनकी आवश्यकता क्यों है?
जेनेरिक्स (या सामान्यीकृत प्रकार) आपको फ़ंक्शन, स्ट्रक्चर और मेथड लिखने की अनुमति देते हैं जो किसी भी डेटा प्रकार के साथ काम करते हैं, साथ ही सख्त टाइपिंग बनाए रखते हैं। इसका मतलब है कि आप एक फ़ंक्शन लिख सकते हैं जो संख्याओं, स्ट्रिंग्स और उपयोगकर्ता-परिभाषित प्रकारों के साथ काम करेगा, बिना कंपाइलेशन चरण में प्रकार की जानकारी खोए।
जेनेरिक्स के आने से पहले, Go डेवलपर्स दो मुख्य दृष्टिकोणों का उपयोग करते थे:
- कोड डुप्लिकेशन —
int,string,float64आदि के लिए अलग-अलग फ़ंक्शन लिखना। - खाली इंटरफ़ेस —
interface{}का उपयोग करके type assertion या रिफ्लेक्शन करना, जो असुरक्षित और धीमा था।
जेनेरिक्स इन समस्याओं को हल करते हैं, जिससे आप सार्वभौमिक, लेकिन टाइप-सुरक्षित कोड लिख सकते हैं। कंपाइलर कंपाइलेशन चरण में प्रकारों की जाँच करता है, जो रनटाइम त्रुटियों को समाप्त करता है।
Generics का सिंटैक्स: टाइप-पैरामीटर
Go में जेनेरिक्स का मुख्य विचार टाइप-पैरामीटर (type parameters) है। उन्हें फ़ंक्शन या प्रकार के नाम के बाद वर्गाकार कोष्ठक में घोषित किया जाता है।
आइए एक सरल उदाहरण देखें — एक फ़ंक्शन जो दो मानों में से न्यूनतम लौटाता है:
package main
import "fmt"
// टाइप-पैरामीटर T के साथ सामान्यीकृत फ़ंक्शनfunc Min[T comparable](a, b T) T { if a < b { return a } return b}
func main() { fmt.Println(Min[int](10, 20)) // 10 fmt.Println(Min[string]("a", "b")) // "a" fmt.Println(Min(3.14, 2.71)) // 2.71 (प्रकार स्वचालित रूप से निकाला जाता है)}यहाँ T एक टाइप-पैरामीटर है। comparable एक बाधा (constraint) है, जो बताती है कि प्रकार T को तुलना ऑपरेटरों का समर्थन करना चाहिए। इस बाधा के बिना, कंपाइलर < के उपयोग की अनुमति नहीं देगा।
महत्वपूर्ण: Go तर्कों से टाइप-पैरामीटर को स्वचालित रूप से निकाल सकता है, इसलिए अधिकांश मामलों में आपको उन्हें स्पष्ट रूप से निर्दिष्ट करने की आवश्यकता नहीं है।
Go जेनेरिक्स में बाधाएं (Constraints)
बाधाएं जेनेरिक्स का एक प्रमुख तत्व हैं। वे परिभाषित करती हैं कि टाइप-पैरामीटर के लिए कौन से ऑपरेशन अनुमत हैं। बाधाओं के बिना, कंपाइलर नहीं जानता कि T पर कौन से मेथड या ऑपरेटर लागू किए जा सकते हैं।
Go में कई अंतर्निहित बाधाएं हैं:
any—interface{}का पर्यायवाची, किसी भी प्रकार की अनुमति देता है।comparable— उन प्रकारों की अनुमति देता है जो==और!=का समर्थन करते हैं।constraints.Ordered— पैकेजgolang.org/x/exp/constraintsसे, सभी क्रमबद्ध प्रकारों (संख्या और स्ट्रिंग) की अनुमति देता है।
आप इंटरफ़ेस का उपयोग करके अपनी स्वयं की बाधाएं भी बना सकते हैं:
package main
import "fmt"
// स्वयं की बाधा: प्रकार में String() मेथड होना चाहिएtype Stringer interface { String() string}
// फ़ंक्शन जो किसी भी Stringer के साथ काम करता हैfunc Print[T Stringer](value T) { fmt.Println(value.String())}
type User struct { Name string}
func (u User) String() string { return "User: " + u.Name}
func main() { user := User{Name: "Alice"} Print(user) // User: Alice}ध्यान दें: Go 1.18+ में, इंटरफ़ेस को बाधाओं के रूप में उपयोग किया जा सकता है, और उनमें न केवल मेथड बल्कि विशिष्ट प्रकार भी शामिल हो सकते हैं।
```