Kotlin Generics: कोणीय कोष्ठकों से डरना छोड़ें और स्वच्छ कोड लिखें

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

परिचय: Generics डरावने नहीं, बल्कि सुविधाजनक क्यों हैं

\n\n

कल्पना करें कि आप एक 'बक्सा' क्लास लिख रहे हैं। इसमें आप कुछ भी रख सकते हैं: किताब, सेब, फ़ोन। लेकिन अगर आप इसे Object के लिए बनाते हैं, तो हर बार निकालते समय as? Book करना होगा और ClassCastException से बचने की प्रार्थना करनी होगी। परिचित लग रहा है?

\n\n

यहाँ generics (जेनेरिक्स) मदद करते हैं — Kotlin में टाइपिंग का एक शक्तिशाली तंत्र जो आपको टाइप सुरक्षा का त्याग किए बिना लचीला कोड लिखने देता है। इस लेख में हम Kotlin में generics को सरल से जटिल तक समझेंगे: बुनियादी क्लासेस, फंक्शन्स, variance (in/out), reified types और star projections। आप सीखेंगे कि कोड को कैसे साफ़ बनाएं और कंपाइलर को अपना सबसे अच्छा सहयोगी कैसे बनाएं।

\n\n

यह लेख शैक्षिक पोर्टल pythonlib.ru के लिए तैयार किया गया है — आधुनिक प्रोग्रामिंग भाषाओं की दुनिया में आपका मार्गदर्शक।

\n\n

1. मूल बातें: Kotlin में Generics क्या है?

\n\n

Generics (सामान्यीकृत प्रकार) आपको क्लासेस, इंटरफ़ेस और फंक्शन्स को एक प्रकार (type) के साथ पैरामीटराइज़ करने की अनुमति देते हैं, जो उपयोग के समय निर्दिष्ट किया जाता है। यह कोड की नकल से बचाता है और कंपाइलेशन के समय प्रकारों पर नियंत्रण देता है।

\n\n

सबसे सरल उदाहरण देखें:

\n\n
class Box<T>(val item: T)\n\nfun main() {\n    val bookBox = Box<String>("Kotlin in Action")\n    val intBox = Box<Int>(42)\n    // कंपाइलर को प्रकार पता है!\n    val title: String = bookBox.item\n}
\n\n

मुख्य बिंदु:

\n
    \n
  • <T> — प्रकार पैरामीटर (कोई भी अक्षर हो सकता है, लेकिन परंपरा के अनुसार T, R, E, K, V)।
  • \n
  • प्रकार ऑब्जेक्ट बनाते समय तय हो जाता है — रनटाइम पर कोई कास्टिंग नहीं।
  • \n
  • Generics केवल कंपाइलेशन समय पर काम करते हैं (type erasure), लेकिन Kotlin 'reification' जोड़ता है (इस पर बाद में)।
  • \n
\n\n

Generic फंक्शन्स

\n

Kotlin में टाइपिंग फंक्शन्स के लिए भी काम करती है। उदाहरण के लिए, एक फंक्शन जो सूची का पहला तत्व लौटाता है:

\n\n
fun <T> firstItem(list: List<T>): T? = list.firstOrNull()\n\nfun main() {\n    val numbers = listOf(1, 2, 3)\n    val first: Int? = firstItem(numbers) // T = Int\n    println(first) // 1\n}
\n\n

ध्यान दें: Kotlin संदर्भ से प्रकार का अनुमान लगा सकता है — firstItem<Int>(numbers) लिखना आवश्यक नहीं है।

\n\n

2. Variance: in और out — टाइप सुरक्षा कैसे न तोड़ें

\n\n

शुरुआती लोगों के लिए सबसे कठिन विषय है variance (वेरिएंस)। यह इस प्रश्न का उत्तर देता है: क्या List<String>, List<Any> का उप-प्रकार हो सकता है?

\n\n

Java में इसे wildcard's (? extends / ? super) से हल किया जाता है। Kotlin में — out और in से।

\n\n

out (कोवेरिएंस) — केवल पढ़ने के लिए

\n

out चिह्न का अर्थ है कि generic प्रकार केवल 'दिया' जा सकता है (मेथड से लौटाया जा सकता है)। उदाहरण — List<out T>।

\n\n
interface Source<out T> {\n    fun next(): T  // OK: T आउटपुट पर\n    // fun add(item: T) // त्रुटि! T इनपुट पर प्रतिबंधित\n}\n\nfun demo(source: Source<String>) {\n    val anySource: Source<Any> = source // out इसे अनुमति देता है\n}
\n\n

यह सुरक्षित क्यों है? अगर हम स्रोत से केवल String पढ़ सकते हैं, तो इसे Any का स्रोत माना जा सकता है।

\n\n

in (कॉन्ट्रावेरिएंस) — केवल लिखने के लिए

\n

in — इसके विपरीत: प्रकार केवल इनपुट पर हो सकता है। क्लासिक उदाहरण — Comparable।

\n\n
interface Comparable<in T> {\n    operator fun compareTo(other: T): Int\n}\n\nfun demo(comp: Comparable<Number>) {\n    val intComp: Comparable<Int> = comp // in इसे अनुमति देता है\n}
\n\n

अगर Comparable<Number> किसी भी संख्या की तुलना कर सकता है, तो वह निश्चित रूप से Int की भी तुलना करेगा।

\n\n

in out (इनवेरिएंस) — डिफ़ॉल्ट

\n

अगर न तो in और न ही out निर्दिष्ट किया गया है, तो प्रकार इनवेरिएंट है। इसका मतलब है कि Box<String> और Box<Any> एक-दूसरे से संबंधित नहीं हैं।

ब्लॉग

पुस्तक अनुशंसाएँ