परिचय: Generics क्या हैं और Go में क्यों आए?
\nलंबे समय तक, Go (Golang) भाषा उन कुछ आधुनिक भाषाओं में से एक थी जिसमें जेनेरिक प्रोग्रामिंग (generics) का समर्थन नहीं था। डेवलपर्स को या तो विभिन्न डेटा प्रकारों के लिए कोड दोहराना पड़ता था, या इंटरफ़ेस और खाली interface{} का उपयोग करना पड़ता था, जिससे टाइप सुरक्षा खत्म हो जाती थी और रनटाइम पर टाइप कास्टिंग करनी पड़ती थी।
Go संस्करण 1.18 (फरवरी 2022) के आने के साथ, भाषा में लंबे समय से प्रतीक्षित जेनेरिक्स शामिल किए गए। Generics एक ऐसा तंत्र है जो आपको ऐसे फंक्शन, टाइप और डेटा स्ट्रक्चर लिखने की अनुमति देता है जो किसी भी प्रकार के साथ काम कर सकते हैं, और साथ ही कंपाइल समय पर सख्त टाइपिंग बनाए रखते हैं।
\nइस लेख में हम जानेंगे:
\n- \n
- Go में जेनेरिक्स की आवश्यकता क्यों है; \n
- जेनेरिक फंक्शन और टाइप कैसे घोषित करें; \n
- Constraints क्या हैं और उनका उपयोग कैसे करें; \n
- व्यावहारिक उपयोग के उदाहरण। \n
Go में Generics की आवश्यकता क्यों है?
\nजेनेरिक्स के आने से पहले, एक सामान्य समस्या यह थी: एक ऐसा फंक्शन लिखना जो विभिन्न प्रकारों (जैसे int, string, float64) के स्लाइस के साथ काम करे।
जेनेरिक्स के बिना तीन अलग-अलग फंक्शन लिखने पड़ते थे:
\nfunc SumInts(nums []int) int {\n total := 0\n for _, v := range nums {\n total += v\n }\n return total\n}\n\nfunc SumFloats(nums []float64) float64 {\n total := 0.0\n for _, v := range nums {\n total += v\n }\n return total\n}\n\nया फिर interface{} का उपयोग करके टाइप कास्टिंग करनी पड़ती थी - जो असुरक्षित और असुविधाजनक है।
जेनेरिक्स के साथ सिर्फ एक फंक्शन काफी है:
\nfunc Sum[T int | float64](nums []T) T {\n var total T\n for _, v := range nums {\n total += v\n }\n return total\n}\n\nफायदे स्पष्ट हैं:
\n- \n
- टाइप सुरक्षा - टाइप की गलतियाँ कंपाइल समय पर ही पकड़ी जाती हैं; \n
- कोड दोहराव में कमी - एक फंक्शन कई प्रकारों के लिए काम करता है; \n
- पठनीयता - कोड अधिक संक्षिप्त और समझने में आसान हो जाता है। \n
Go में Generics का मूल सिंटैक्स
\nजेनेरिक फंक्शन घोषित करना
\nमूल सिंटैक्स में टाइप पैरामीटर निर्दिष्ट करने के लिए वर्गाकार कोष्ठक [] का उपयोग किया जाता है:
func फंक्शननाम[टाइपनाम constraint](पैरामीटर) परिणाम {\n // फंक्शन का मुख्य भाग\n}\n\nएक सरल फंक्शन का उदाहरण जो दिए गए मान को वापस लौटाता है:
\nfunc Identity[T any](value T) T {\n return value\n}\n\nfunc main() {\n fmt.Println(Identity[int](42)) // 42\n fmt.Println(Identity[string]("Go")) // Go\n}\n\nGo स्वचालित रूप से टाइप का अनुमान लगा सकता है, इसलिए [int] स्पष्ट रूप से लिखना ज़रूरी नहीं है:
fmt.Println(Identity(42)) // Go खुद समझ जाएगा कि T = int\nfmt.Println(Identity("Go")) // T = string\n\n\nजेनेरिक टाइप (स्ट्रक्चर)
\nजेनेरिक्स सिर्फ फंक्शन के साथ ही नहीं, बल्कि यूज़र-डिफ़ाइंड टाइप के साथ भी काम करते हैं:
\ntype Stack[T any] struct {\n elements []T\n}\n\nfunc (s *Stack[T]) Push(value T) {\n s.elements = append(s.elements, value)\n}\n\nfunc (s *Stack[T]) Pop() (T, bool) {\n if len(s.elements) == 0 {\n var zero T\n return zero, false\n }\n value := s.elements[len(s.elements)-1]\n s.elements = s.elements[:len(s.elements)-1]\n return value, true\n}\n\nfunc main() {\n intStack := Stack[int]{}\n intStack.Push(10)\n intStack.Push(20)\n val, ok := intStack.Pop()\n fmt.Println(val, ok) // 20 true\n}\n\n\nConstraints: टाइप के लिए प्रतिबंध
\nऊपर के उदाहरणों में हमने any का उपयोग किया - यह एक बिल्ट-इन constraint है जिसका अर्थ है "कोई भी टाइप"। हालांकि, अक्सर प्रतिबंध लगाने की आवश्यकता होती है: उदाहरण के लिए, टाइप को तुलना या अंकगणितीय संक्रियाओं का समर्थन करना चाहिए।