Kotlin में Generics: क्यों ज़रूरी हैं और व्यवहार में कैसे उपयोग करें
\n\nGenerics (सामान्यीकरण) Kotlin भाषा की प्रमुख विशेषताओं में से एक है, जो आपको अधिक लचीला, टाइप-सुरक्षित और पुन: प्रयोज्य कोड लिखने की अनुमति देता है। यदि आपने कभी List<String> या Map<Int, User> लिखा है, तो आप पहले ही जेनेरिक्स का सामना कर चुके हैं। लेकिन वास्तव में इनकी आवश्यकता क्यों है और उनसे अधिकतम लाभ कैसे उठाएं? इस लेख में हम सिद्धांत को समझेंगे और वास्तविक उदाहरणों के साथ अभ्यास की ओर बढ़ेंगे।
समस्या जिसे Generics हल करते हैं
\n\nकल्पना करें कि आपको एक फ़ंक्शन लिखना है जो सूची से पहला तत्व लौटाता है। जेनेरिक्स के बिना, आपको प्रत्येक डेटा प्रकार के लिए अलग फ़ंक्शन लिखना होगा:
\n\nfun getFirstString(list: List<String>): String? = list.firstOrNull()\nfun getFirstInt(list: List<Int>): Int? = list.firstOrNull()\nfun getFirstUser(list: List<User>): User? = list.firstOrNull()\n\nइससे कोड की पुनरावृत्ति होती है। Any का उपयोग समस्या को हल करेगा, लेकिन आप संकलन चरण में प्रकार की जानकारी खो देंगे:
fun getFirst(list: List<Any>): Any? = list.firstOrNull()\n\n// प्रकार रूपांतरण करना होगा\nval name: String? = getFirst(strings) as? String\n\nGenerics इस समस्या को सुंदरता से हल करते हैं:
\n\nfun <T> getFirst(list: List<T>): T? = list.firstOrNull()\n\n// कंपाइलर प्रकार जानता है!\nval name: String? = getFirst(listOf("Alice", "Bob"))\nval age: Int? = getFirst(listOf(25, 30))\n\nअब एक फ़ंक्शन किसी भी प्रकार के साथ काम करता है, पूर्ण टाइप सुरक्षा बनाए रखते हुए।
\n\nKotlin में Generics की मूल बातें: सिंटैक्स और घोषणा
\n\nसामान्यीकरण को कोण कोष्ठक <T> के साथ घोषित किया जाता है। अक्षर T केवल एक परंपरा है, आप किसी भी नाम का उपयोग कर सकते हैं: E (तत्व), K (कुंजी), V (मान)।
Generic-क्लासेस
\n\nclass Box<T>(val value: T) {\n fun getContent(): T = value\n}\n\nfun main() {\n val stringBox = Box("Hello")\n val intBox = Box(42)\n \n println(stringBox.getContent()) // Hello\n println(intBox.getContent()) // 42\n}\n\nGeneric-फ़ंक्शन
\n\nfun <T> printItem(item: T) {\n println("Item: $item")\n}\n\n// प्रकार स्पष्ट रूप से निर्दिष्ट किया जा सकता है\nprintItem<String>("Kotlin")\n// या प्रकार अनुमान पर निर्भर रहें\nprintItem(100)\n\nGeneric-इंटरफ़ेस
\n\ninterface Repository<T> {\n fun getById(id: Int): T\n fun save(item: T): Boolean\n}\n\nclass UserRepository : Repository<User> {\n override fun getById(id: Int): User { /* ... */ }\n override fun save(item: User): Boolean { /* ... */ }\n}\n\nपरिवर्तनशीलता: in, out और तारांकन चिह्न *
\n\nKotlin की सबसे शक्तिशाली क्षमताओं में से एक परिवर्तनशीलता (variance) है। यह इस प्रश्न का उत्तर देती है: क्या List<String>, List<Any> का उपप्रकार हो सकता है?
सहप्रसरण (out)
\n\nout का उपयोग करें जब आपका generic-प्रकार केवल लौटाया जाता है (producer)। उदाहरण के लिए, List<T> सहप्रसरणीय है:
// आप List<String> को List<Any> वेरिएबल में असाइन कर सकते हैं\nval strings: List<String> = listOf("a", "b")\nval anyList: List<Any> = strings // OK!\n\n// लेकिन आप तत्व नहीं जोड़ सकते\n// anyList.add(1) // संकलन त्रुटि!\n\nस्वयं का उदाहरण:
\n\nclass Producer<out T>(private val value: T) {\n fun produce(): T = value\n}\n\nfun main() {\n val stringProducer: Producer<String> = Producer("Hello")\n val anyProducer: Producer<Any> = stringProducer // काम करता है!\n println(anyProducer.produce())\n}\n\nप्रतिप्रसरण (in)
\n\nin का उपयोग करें जब प्रकार केवल स्वीकार किया जाता है (consumer)। उदाहरण के लिए, Comparable<T>:
ब्लॉग
पुस्तक अनुशंसाएँ
यह भी पढ़ें