यह कोडलैब प्रोग्रामर कोर्स के लिए Kotlin बूटकैंप का हिस्सा है. अगर आप कोडलैब के क्रम में काम करते हैं, तो आपको इस कोर्स का ज़्यादा से ज़्यादा फ़ायदा मिलेगा. अपनी जानकारी के आधार पर, आप कुछ सेक्शन को हाइलाइट कर सकते हैं. यह कोर्स उन प्रोग्रामर को ध्यान में रखकर बनाया गया है जो ऑब्जेक्ट पर आधारित भाषा जानते हैं और कोटलिन सीखना चाहते हैं.
परिचय
इस कोडलैब में आपको सामान्य क्लास, फ़ंक्शन, और तरीकों के बारे में बताया गया है. साथ ही, यह भी बताया गया है कि वे Kotlin में कैसे काम करते हैं.
सिर्फ़ एक नमूने वाला ऐप्लिकेशन बनाने के बजाय, इस कोर्स के पाठ आपकी जानकारी देने के लिए डिज़ाइन किए गए हैं. हालांकि, आप एक-दूसरे से खुद को अलग नहीं कर सकते हैं, ताकि आप उन सेक्शन को हाइलाइट कर सकें जिनसे आप सहमत हैं. इन्हें एक साथ जोड़ने के लिए, कई उदाहरणों में एक्वेरियम की थीम का इस्तेमाल किया गया है. अगर आप पूरी अक्वेरियम की कहानी देखना चाहते हैं, तो प्रोग्रामर के लिए Kotlin बूटकैंप Udacity कोर्स देखें.
आपको क्या पता होना चाहिए
- Kotlin के फ़ंक्शन, क्लास, और मेथड का सिंटैक्स
- IntelliJ IDEA में नई क्लास बनाने और कोई प्रोग्राम चलाने का तरीका
आप इन चीज़ों के बारे में जानेंगे
- जेनरिक क्लास, तरीकों, और फ़ंक्शन के साथ काम करने का तरीका
आप क्या कर पाएंगे!
- जेनरिक क्लास बनाना और कंस्ट्रेंट जोड़ना
in
औरout
टाइप बनाएं- जेनरिक फ़ंक्शन, मेथड, और एक्सटेंशन फ़ंक्शन बनाएं
जेनरिक के बारे में जानकारी
Kotlin में कई तरह की प्रोग्रामिंग भाषाएं होती हैं. जेनरिक टाइप की मदद से, आप क्लास को सामान्य बना सकते हैं. इससे क्लास को ज़्यादा सुविधाजनक बनाया जा सकता है.
मान लें कि आप एक MyList
क्लास लागू कर रहे थे जिसमें आइटम की सूची है. जेनरिक के बिना, आपको हर तरह के MyList
के लिए एक नया वर्शन लागू करना होगा: Double
के लिए एक, String
के लिए एक, Fish
के लिए एक. जेनरिक के साथ, आप सूची को जेनरिक बना सकते हैं, ताकि वह किसी भी तरह का ऑब्जेक्ट होल्ड कर सके. यह एक तरह का वाइल्डकार्ड बनाता है, जो कई तरह के फ़िट हो सकता है.
जेनरिक टाइप को परिभाषित करने के लिए, क्लास के नाम के बाद T ऐंगल ब्रैकेट <T>
का इस्तेमाल करें. (आप किसी दूसरे अक्षर या लंबे नाम का इस्तेमाल कर सकते हैं, लेकिन जेनरिक टाइप की परंपरा T है.)
class MyList<T> {
fun get(pos: Int): T {
TODO("implement")
}
fun addItem(item: T) {}
}
आप T
का इस्तेमाल किसी सामान्य टाइप की तरह कर सकते हैं. get()
का रिटर्न टाइप T
है और addItem()
का पैरामीटर T
है. हालांकि, सामान्य सूचियां बहुत काम की होती हैं, इसलिए Kotlin में List
क्लास पहले से मौजूद होती है.
पहला चरण: टाइप हैरारकी बनाना
इस कदम में आप अगले चरण में इस्तेमाल करने के लिए कुछ क्लास बनाते हैं. सब-क्लासिंग को पहले के कोडलैब में शामिल किया गया था. हालांकि, यहां कम शब्दों में समीक्षा की गई है.
- उदाहरण को व्यवस्थित रखने के लिए, src में एक नया पैकेज बनाएं और इसे
generics
नाम दें. - सामान्य पैकेज में, एक नई
Aquarium.kt
फ़ाइल बनाएं. इससे आप बिना किसी टकराव के एक जैसे नाम का इस्तेमाल करके चीज़ों को फिर से तय कर सकते हैं, इसलिए इस कोडलैब के लिए आपका बाकी कोड इस फ़ाइल में चला जाता है. - पानी की सप्लाई के प्रकारों को क्रम से लगाना.
WaterSupply
कोopen
क्लास बनाकर शुरू करें, ताकि उन्हें सब-क्लास किया जा सके. - बूलियन
var
पैरामीटर,needsProcessing
जोड़ें. इससे गैटर और सेटर के साथ अपने-आप एक बदली जा सकने वाली प्रॉपर्टी बन जाती है. - एक सब-क्लास
TapWater
बनाएं, जोWaterSupply
तक बढ़ती है. साथ ही,true
कोneedsProcessing
के लिए पास करें, क्योंकि टैप वॉटर में ऐसी चीज़ें होती हैं जो मछली के लिए खराब होती हैं. TapWater
में,addChemicalCleaners()
नाम के फ़ंक्शन के बारे में बताएं, जो पानी को साफ़ करने के बादneedsProcessing
कोfalse
पर सेट करता है.needsProcessing
प्रॉपर्टी कोTapWater
से सेट किया जा सकता है, क्योंकि यह डिफ़ॉल्ट रूप सेpublic
होती है और सब-क्लास से ऐक्सेस की जा सकती है. यह रहा पूरा कोड.
package generics
open class WaterSupply(var needsProcessing: Boolean)
class TapWater : WaterSupply(true) {
fun addChemicalCleaners() {
needsProcessing = false
}
}
WaterSupply
के दो और सब-क्लास बनाएं, जिन्हेंFishStoreWater
औरLakeWater
कहा जाता है.FishStoreWater
को प्रोसेस करने की ज़रूरत नहीं है, लेकिनLakeWater
कोfilter()
तरीके का इस्तेमाल करके फ़िल्टर करना ज़रूरी है. फ़िल्टर करने के बाद, इसे फिर से प्रोसेस करने की ज़रूरत नहीं होती. इसलिए,filter()
मेंneedsProcessing = false
सेट करें.
class FishStoreWater : WaterSupply(false)
class LakeWater : WaterSupply(true) {
fun filter() {
needsProcessing = false
}
}
अगर आपको ज़्यादा जानकारी चाहिए, तो Kotlin में इनहेरिट करने के बारे में पहले दिए गए लेसन को देखें.
दूसरा चरण: जेनरिक क्लास बनाना
इस तरीके से आप Aquarium
क्लास में बदलाव करके अलग-अलग तरह के वॉटर सप्लाई के लिए काम कर पाएंगे.
- Aquarium.kt में
Aquarium
को परिभाषित करें. इसके बाद, क्लास के नाम के बाद ब्रैकेट में<T>
लगाएं. Aquarium
मेंT
टाइप कीwaterSupply
नहीं बदली जा सकने वाली प्रॉपर्टी जोड़ें.
class Aquarium<T>(val waterSupply: T)
genericsExample()
नाम का फ़ंक्शन लिखें. यह #39; क्लास का हिस्सा नहीं है, इसलिए यह फ़ाइल के टॉप लेवल पर जा सकता है, जैसे किmain()
फ़ंक्शन या क्लास की परिभाषाएं. फ़ंक्शन में,Aquarium
बनाएं और उसेWaterSupply
पास करें.waterSupply
पैरामीटर जेनरिक है, इसलिए आपको ऐंगल ब्रैकेट<>
में टाइप तय करना होगा.
fun genericsExample() {
val aquarium = Aquarium<TapWater>(TapWater())
}
genericsExample()
में आपका कोड, अक्वेरियम और #39 कीwaterSupply
को ऐक्सेस कर सकता है. यहTapWater
टाइप का है, इसलिए आप किसी भी तरह के कास्ट के बिनाaddChemicalCleaners()
को कॉल कर सकते हैं.
fun genericsExample() {
val aquarium = Aquarium<TapWater>(TapWater())
aquarium.waterSupply.addChemicalCleaners()
}
Aquarium
ऑब्जेक्ट बनाते समय, आप ऐंगल ब्रैकेट और उनके बीच के #&336 को हटा सकते हैं, क्योंकि Kotlin में टाइप का अनुमान होता है. इसलिए, इंस्टेंस बनाते समयTapWater
को दो बार बोलने की ज़रूरत नहीं है. यह टाइप,Aquarium
के तर्क के हिसाब से लगाया जा सकता है. इससे अब भीTapWater
टाइप काAquarium
बन जाएगा.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
aquarium.waterSupply.addChemicalCleaners()
}
- यह देखने के लिए कि क्या हो रहा है,
needsProcessing
कोaddChemicalCleaners()
पर कॉल करने से पहले और बाद में प्रिंट करें. नीचे पूरा किया गया फ़ंक्शन है.
fun genericsExample() {
val aquarium = Aquarium<TapWater>(TapWater())
println("water needs processing: ${aquarium.waterSupply.needsProcessing}")
aquarium.waterSupply.addChemicalCleaners()
println("water needs processing: ${aquarium.waterSupply.needsProcessing}")
}
genericsExample()
को कॉल करने के लिएmain()
फ़ंक्शन जोड़ें. इसके बाद, अपना प्रोग्राम चलाएं और नतीजे की निगरानी करें.
fun main() {
genericsExample()
}
⇒ water needs processing: true water needs processing: false
तीसरा चरण: प्रॉडक्ट की सेटिंग को ज़्यादा सटीक बनाना
जेनेरिक का मतलब है कि आप करीब-करीब सब कुछ पास कर सकते हैं, और कभी-कभी कोई समस्या हो सकती है. इस चरण में आप यह तय कर सकते हैं कि Aquarium
क्लास में क्या डाला जा सकता है.
genericsExample()
में,waterSupply
के लिए स्ट्रिंग पास करने वालाAquarium
बनाएं. इसके बाद, एक्वेरियम और #39; कीwaterSupply
प्रॉपर्टी प्रिंट करें.
fun genericsExample() {
val aquarium2 = Aquarium("string")
println(aquarium2.waterSupply)
}
- प्रोग्राम को चलाकर देखें.
⇒ string
नतीजे के तौर पर, पास की गई स्ट्रिंग मान्य होती है. ऐसा इसलिए, क्योंकि Aquarium
T.
पर कोई पाबंदी नहीं लगाता है. इसमें String
भी शामिल है.
genericsExample()
मेंwaterSupply
के लिएnull
पास करने वाला एक औरAquarium
बनाएं. अगरwaterSupply
शून्य है, तो"waterSupply is null"
का प्रिंट लें.
fun genericsExample() {
val aquarium3 = Aquarium(null)
if (aquarium3.waterSupply == null) {
println("waterSupply is null")
}
}
- प्रोग्राम चलाएं और नतीजों पर ध्यान दें.
⇒ waterSupply is null
Aquarium
बनाते समय आप null
को क्यों पास कर सकते हैं? ऐसा इसलिए होता है, क्योंकि T
डिफ़ॉल्ट रूप से शून्य होने वाले Any?
टाइप का होता है, जो टाइप हैरारकी के ऊपर होता है. यह आपके टाइप किए गए शब्दों के बराबर है.
class Aquarium<T: Any?>(val waterSupply: T)
- अगर आप
null
को पास करने की अनुमति नहीं देना चाहते, तोAny
के बाद?
को हटाकर,T
टाइप काAny
साफ़ तौर पर बताएं.
class Aquarium<T: Any>(val waterSupply: T)
इस कॉन्टेक्स्ट में, Any
को सामान्य कंस्ट्रेंट कहा जाता है. इसका मतलब है कि T
के लिए कोई भी टाइप पास किया जा सकता है. ज़रूरी है कि यह null
हो.
- आपको यह पक्का करना है कि
T
के लिए सिर्फ़WaterSupply
(या इसके सब-क्लास में से कोई एक) पास किया जाना चाहिए. ज़्यादा खास सामान्य कंस्ट्रेंट के बारे में बताने के लिए,Any
कोWaterSupply
से बदलें.
class Aquarium<T: WaterSupply>(val waterSupply: T)
चौथा चरण: ज़्यादा जांच जोड़ना
इस कदम में, आपको check()
फ़ंक्शन के बारे में पता चलता है. इससे यह पक्का करने में मदद मिलती है कि आपका कोड उम्मीद के मुताबिक काम कर रहा है या नहीं. check()
फ़ंक्शन, Kotlin में एक स्टैंडर्ड लाइब्रेरी फ़ंक्शन है. यह दावे के तौर पर काम करता है. अगर इसके आर्ग्युमेंट का आकलन false
पर होता है, तो यह IllegalStateException
का इस्तेमाल करेगा.
check()
जोड़ने के साथ,Aquarium
की क्लास मेंaddWater()
जोड़ने का तरीका जोड़ें. इससे यह पक्का हो जाएगा कि आपको पहले पानी प्रोसेस करने की ज़रूरत नहीं है.
class Aquarium<T: WaterSupply>(val waterSupply: T) {
fun addWater() {
check(!waterSupply.needsProcessing) { "water supply needs processing first" }
println("adding water from $waterSupply")
}
}
इस मामले में, अगर needsProcessing
सही है, तो check()
एक अपवाद रिटर्न करेगा.
genericsExample()
में, कोड जोड़करLakeWater
के साथAquarium
बनाएं, फिर उसमें पानी डालें.
fun genericsExample() {
val aquarium4 = Aquarium(LakeWater())
aquarium4.addWater()
}
- अपना प्रोग्राम चलाएं और आपको एक अपवाद मिलेगा, क्योंकि पहले पानी को फ़िल्टर करना होगा.
⇒ Exception in thread "main" java.lang.IllegalStateException: water supply needs processing first at Aquarium.generics.Aquarium.addWater(Aquarium.kt:21)
Aquarium
को पानी में जोड़ने से पहले, फ़िल्टर करने के लिए एक कॉल जोड़ें. प्रोग्राम चलाने पर, अब कोई अपवाद नहीं दिखेगा.
fun genericsExample() {
val aquarium4 = Aquarium(LakeWater())
aquarium4.waterSupply.filter()
aquarium4.addWater()
}
⇒ adding water from generics.LakeWater@880ec60
ऊपर दी गई बुनियादी जानकारी में बुनियादी बातें बताई गई हैं. इन टास्क में और भी चीज़ें शामिल हैं, लेकिन ज़रूरी है कि आप जेनरिक कंस्ट्रेंट के साथ जेनरिक क्लास का एलान करें और उसका इस्तेमाल करें.
इस टास्क में, आप जेनरिक विज्ञापनों के साथ इन और आउट टाइप के बारे में जान सकते हैं. in
टाइप टाइप को सिर्फ़ क्लास में पास किया जा सकता है, रिटर्न नहीं. out
एक ऐसा टाइप है जिसे सिर्फ़ क्लास से लौटाया जा सकता है.
Aquarium
क्लास पर नज़र डालें और आप देख पाएंगे कि #39; जेनरिक टाइप सिर्फ़ waterSupply
प्रॉपर्टी पाने पर ही दिखेगा. कोई भी ऐसा तरीका नहीं है जो T
टाइप की वैल्यू को पैरामीटर के तौर पर लेता हो (कंस्ट्रक्टर में इसे परिभाषित करने के अलावा). Kotlin की मदद से, इस केस के लिए out
टाइप को तय किया जा सकता है. साथ ही, इससे यह भी पता लगाया जा सकता है कि टाइप कहां इस्तेमाल किए जा सकते हैं. इसी तरह, आप सामान्य टाइप के लिए in
टाइप तय करें, जो सिर्फ़ मेथड में पास किए जाते हैं, न कि रिटर्न किए गए. इससे Kotlin को कोड की सुरक्षा के लिए ज़्यादा जांच करने की अनुमति मिल जाती है.
in
और out
टाइप, Kotlin's टाइप सिस्टम के लिए निर्देश हैं. पूरे टाइप के सिस्टम को समझाना इस बूटकैंप के दायरे से बाहर है(&&30; बहुत शामिल है); हालांकि, कंपाइलर ऐसे टाइप को फ़्लैग करेगा जिन्हें in
और out
सही तरीके से मार्क न किया गया हो, इसलिए आपको उनके बारे में जानना चाहिए.
पहला चरण: आउट टाइप के बारे में बताना
Aquarium
क्लास में,T: WaterSupply
कोout
टाइप में बदलें.
class Aquarium<out T: WaterSupply>(val waterSupply: T) {
...
}
- उसी फ़ाइल में, क्लास के बाहर,
addItemTo()
फ़ंक्शन का एलान करें, जोWaterSupply
केAquarium
की उम्मीद करता है.
fun addItemTo(aquarium: Aquarium<WaterSupply>) = println("item added")
genericsExample()
सेaddItemTo()
को कॉल करें और अपना प्रोग्राम चलाएं.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
addItemTo(aquarium)
}
⇒ item added
Kotlin में addItemTo()
यह पक्का कर सकता है कि आम तौर पर इस्तेमाल होने वाली WaterSupply
नीति का उल्लंघन करने की वजह से, किसी भी तरह का नुकसान नहीं होता है. ऐसा इसलिए होता है, क्योंकि इसे out
के तौर पर बताया जाता है.
out
कीवर्ड हटाने पर, कंपाइलरaddItemTo()
पर कॉल करते समय गड़बड़ी का मैसेज देगा, क्योंकि Kotlin में यह पक्का नहीं हो सकता कि आप टाइप के साथ असुरक्षित काम नहीं कर रहे हैं.
दूसरा चरण: टाइप टाइप के बारे में बताना
in
टाइप, out
टाइप की तरह ही होता है, लेकिन सामान्य टाइप के लिए, जिन्हें सिर्फ़ फ़ंक्शन में पास किया जाता है, न कि रिटर्न. अगर आप in
टाइप दिखाने की कोशिश करते हैं, तो आपको कंपाइल से जुड़ी गड़बड़ी दिखेगी. इस उदाहरण में आप एक इंटरफ़ेस के हिस्से के रूप में एक in
प्रकार तय करेंगे.
- Aquarium.kt में ऐसा इंटरफ़ेस
Cleaner
तय करें जोWaterSupply
तक सीमित एक सामान्यT
लेता है. इसका इस्तेमाल सिर्फ़clean()
में आर्ग्युमेंट के तौर पर किया जाता है. इसलिए, आप इसेin
पैरामीटर बना सकते हैं.
interface Cleaner<in T: WaterSupply> {
fun clean(waterSupply: T)
}
Cleaner
इंटरफ़ेस का इस्तेमाल करने के लिए,TapWaterCleaner
क्लास बनाएं, जोCleaner
कोTapWater
से जुड़े हुए मिले, क्योंकि इसमें केमिकल जोड़े जा सकते हैं.
class TapWaterCleaner : Cleaner<TapWater> {
override fun clean(waterSupply: TapWater) = waterSupply.addChemicalCleaners()
}
Aquarium
क्लास में,addWater()
कोT
टाइप करने के लिएCleaner
अपडेट करें और जोड़ने से पहले पानी साफ़ करें.
class Aquarium<out T: WaterSupply>(val waterSupply: T) {
fun addWater(cleaner: Cleaner<T>) {
if (waterSupply.needsProcessing) {
cleaner.clean(waterSupply)
}
println("water added")
}
}
TapWaterCleaner
,genericsExample()
कोTapWater
के साथ बनाने के लिए,genericsExample()
उदाहरण कोड को अपडेट करें. इसके बाद, क्लीनर का इस्तेमाल करके पानी जोड़ें. ज़रूरत के हिसाब से क्लीनर का इस्तेमाल किया जाएगा.
fun genericsExample() {
val cleaner = TapWaterCleaner()
val aquarium = Aquarium(TapWater())
aquarium.addWater(cleaner)
}
Kotlin में in
और out
टाइप की जानकारी का इस्तेमाल होगा, ताकि यह पक्का किया जा सके कि आपका कोड, जेनरिक कोड सुरक्षित तरीके से इस्तेमाल करे. Out
और in
को याद रखना आसान है: out
प्रकारों को वापस लौटाए गए मानों के रूप में भेजा जा सकता है, in
प्रकारों को तर्कों के रूप में अंदर की ओर भेजा जा सकता है.
अगर आप अलग-अलग तरह की समस्याओं और समस्याओं को हल करने के तरीके के बारे में ज़्यादा जानना चाहते हैं, तो दस्तावेज़ में इन चीज़ों के बारे में ज़्यादा जानकारी दी गई है.
इस टास्क में, आपको जेनरिक फ़ंक्शन और उनके इस्तेमाल के समय की जानकारी मिलेगी. आम तौर पर, जब भी फ़ंक्शन किसी सामान्य टाइप वाली क्लास का आर्ग्युमेंट लेता है, तो जेनरिक फ़ंक्शन बनाना एक अच्छा आइडिया है.
पहला चरण: जेनरिक फ़ंक्शन बनाना
- generics/Aquarium.kt में
isWaterClean()
फ़ंक्शन बनाएं, जिसमेंAquarium
लगता है. आपको पैरामीटर का सामान्य टाइप तय करना होगा;WaterSupply
का इस्तेमाल करना एक विकल्प है.
fun isWaterClean(aquarium: Aquarium<WaterSupply>) {
println("aquarium water is clean: ${aquarium.waterSupply.needsProcessing}")
}
हालांकि, इसका मतलब है कि कॉल करने के लिए, Aquarium
में out
टाइप पैरामीटर होना ज़रूरी है. कभी-कभी out
या in
बहुत ज़्यादा पाबंदी वाली होता है, क्योंकि इनपुट और आउटपुट दोनों के लिए आपको टाइप का इस्तेमाल करना पड़ता है. आप फ़ंक्शन को सामान्य बनाकर out
की ज़रूरी शर्त हटा सकते हैं.
- फ़ंक्शन को जेनरिक बनाने के लिए, कीवर्ड
fun
के बाद जेनरिक टाइपT
और सभी कंस्ट्रेंट के साथ ऐंगल ब्रैकेट रखें. इस मामले मेंWaterSupply
का इस्तेमाल करें.Aquarium
कोWaterSupply
के बजायT
से सीमित होने के लिए सेट करें.
fun <T: WaterSupply> isWaterClean(aquarium: Aquarium<T>) {
println("aquarium water is clean: ${!aquarium.waterSupply.needsProcessing}")
}
T
, isWaterClean()
के लिए एक टाइप पैरामीटर है, जिसका इस्तेमाल एक्वेरियम के सामान्य प्रकार को बताने के लिए किया जा रहा है. यह पैटर्न वाकई बहुत आम है और इस पर काम करना भी एक अच्छा आइडिया है.
- फ़ंक्शन के नाम के ठीक बाद और ब्रैकेट से पहले,
isWaterClean()
फ़ंक्शन को ऐंगल ब्रैकेट में टाइप करें.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
isWaterClean<TapWater>(aquarium)
}
- तर्क
aquarium
से टाइप के अनुमान की वजह से, टाइप की ज़रूरत' नहीं है, इसलिए इसे हटा दें. अपना प्रोग्राम चलाएं और आउटपुट पर नज़र रखें.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
isWaterClean(aquarium)
}
⇒ aquarium water is clean: false
दूसरा चरण: बेहतर बनाए गए टाइप की मदद से सामान्य तरीका बनाना
आप मेथड के लिए जेनरिक फ़ंक्शन का भी इस्तेमाल कर सकते हैं, उन क्लास के लिए भी जिनका अपना खुद का जेनरिक टाइप होता है. इस चरण में, Aquarium
में एक सामान्य तरीका जोड़ें, जो यह जांचता हो कि उसमें WaterSupply
का टाइप है या नहीं.
Aquarium
क्लास में, एक तरीके का एलान करें,hasWaterSupplyOfType()
जो सामान्य पैरामीटरR
(T
का इस्तेमाल पहले ही हो चुका है) लेता है, वहWaterSupply
तक सीमित है, औरwaterSupply
काR
टाइप होने परtrue
दिखाता है. यह आपके बताए गए फ़ंक्शन की तरह है, लेकिनAquarium
क्लास में.
fun <R: WaterSupply> hasWaterSupplyOfType() = waterSupply is R
- ध्यान दें कि फ़ाइनल
R
को लाल रंग से अंडरलाइन किया गया है. यह देखने के लिए कि गड़बड़ी क्या है, पॉइंटर को उसके ऊपर रखें. is
की जांच करने के लिए, आपको Kotlin को बताना होगा कि टाइप अपडेट किया गया है या वह असली है. फ़ंक्शन में इस्तेमाल किया जा सकता है. ऐसा करने के लिए,inline
कोfun
कीवर्ड के सामने रखें औरreified
को सामान्य प्रकारR
के सामने रखें.
inline fun <reified R: WaterSupply> hasWaterSupplyOfType() = waterSupply is R
किसी टाइप में बदलाव किए जाने के बाद, उसे सामान्य टाइप की तरह इस्तेमाल किया जा सकता है. ऐसा इसलिए, क्योंकि इनलाइन करने के बाद यह असली टाइप का होता है. इसका मतलब है कि इस तरह का इस्तेमाल करके, is
की जांच की जा सकती है.
अगर आप यहां reified
का इस्तेमाल नहीं करते हैं, तो टाइप टाइप &&tt>असल में नहीं रहेगा. Kotlin के लिए, is
की जांच करने की अनुमति देना ज़रूरी है. यह #&330 नहीं है, क्योंकि गैर-बदलाव किए गए प्रकार सिर्फ़ कंपाइल करने के समय उपलब्ध होते हैं और आपके प्रोग्राम से रनटाइम पर उनका इस्तेमाल नहीं किया जा सकता. इस बारे में अगले सेक्शन में ज़्यादा जानकारी दी गई है.
- टाइप के तौर पर
TapWater
पास करें. जेनरिक फ़ंक्शन को कॉल करने की तरह, फ़ंक्शन के नाम के बाद टाइप के साथ ऐंगल ब्रैकेट का इस्तेमाल करके जेनरिक तरीकों को कॉल करें. प्रोग्राम चलाएं और नतीजों पर ध्यान दें.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
println(aquarium.hasWaterSupplyOfType<TapWater>()) // true
}
⇒ true
तीसरा चरण: एक्सटेंशन के फ़ंक्शन बनाना
आप सामान्य फ़ंक्शन और एक्सटेंशन फ़ंक्शन के लिए, बेहतर टाइप का इस्तेमाल भी कर सकते हैं.
Aquarium
क्लास के बाहर,WaterSupply
परisOfType()
नाम का एक एक्सटेंशन फ़ंक्शन तय करें, जो यह जांच करता हो कि पास किया गयाWaterSupply
किसी खास तरह का है या नहीं. उदाहरण के लिए,TapWater
.
inline fun <reified T: WaterSupply> WaterSupply.isOfType() = this is T
- एक्सटेंशन फ़ंक्शन को किसी तरीके की तरह कॉल करें.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
println(aquarium.waterSupply.isOfType<TapWater>())
}
⇒ true
इन एक्सटेंशन फ़ंक्शन के साथ, इससे कोई फ़र्क़ नहीं पड़ता कि Aquarium
किस तरह का है (Aquarium
या TowerTank
या कुछ अन्य सब-क्लास), जब तक कि यह Aquarium
है. स्टार अनुमान सिंटैक्स का इस्तेमाल करना कई तरह के मिलान बताने के लिए आसान है. जब आप स्टार- अनुमान की सुविधा का इस्तेमाल करते हैं, तो Kotlin में यह पक्का किया जाता है कि आप भी कोई असुरक्षित काम न करें.
- स्टार के अनुमान का इस्तेमाल करने के लिए,
Aquarium
के बाद<*>
लगाएं.hasWaterSupplyOfType()
को एक्सटेंशन फ़ंक्शन के रूप में ले जाएं, क्योंकि यहAquarium
के मुख्य एपीआई का हिस्सा नहीं है.
inline fun <reified R: WaterSupply> Aquarium<*>.hasWaterSupplyOfType() = waterSupply is R
- कॉल को
hasWaterSupplyOfType()
में बदलें और अपना प्रोग्राम चलाएं.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
println(aquarium.hasWaterSupplyOfType<TapWater>())
}
⇒ true
पिछले उदाहरण में, आपको जेनरिक टाइप को reified
के तौर पर मार्क करके फ़ंक्शन inline
बनाना था, क्योंकि Kotlin को रनटाइम के दौरान उनके बारे में जानने की ज़रूरत होती है, न कि सिर्फ़ समय कंपाइल करने में.
सभी सामान्य टाइप का इस्तेमाल सिर्फ़ Kotlin में कंपाइल करने के समय किया जाता है. इससे कंपाइलर यह पक्का करता है कि आप सभी काम सुरक्षित तरीके से कर रहे हैं. रनटाइम के हिसाब से सभी सामान्य टाइप को मिटा दिया जाता है. इसलिए, मिटाए गए टाइप को जांचने से पहले मिला गड़बड़ी का मैसेज.
ऐसा लगता है कि कंपाइलर रनटाइम तक जेनरिक टाइप डाले बिना सही कोड बना सकता है. इसका मतलब यह है कि कभी-कभी आप कुछ ऐसा करते हैं, जैसे कि is
सामान्य टाइप की जांच करता है कि कंपाइलर काम नहीं कर सकता ##39; इस वजह से, Kotlin ने नए या असली टाइप जोड़े.
आप Kotlin दस्तावेज़ में, बदलाव किए गए टाइप और डेटा हमेशा के लिए मिटाने के बारे में ज़्यादा पढ़ सकते हैं.
यह लेसन, जेनरिक पर फ़ोकस करता है. ये कोड, ज़्यादा सुविधाजनक और इस्तेमाल करने में आसान बनाने के लिए अहम हैं.
- कोड को ज़्यादा सुविधाजनक बनाने के लिए जेनरिक क्लास बनाएं.
- जेनरिक के साथ इस्तेमाल किए जाने वाले टाइप को सीमित करने के लिए, जेनरिक कंस्ट्रेंट जोड़ें.
- क्लास में पास किए जाने या उससे लौटाए जाने वाले टाइप पर पाबंदी लगाने के लिए, जेनरिक के साथ
in
औरout
टाइप का इस्तेमाल करें. इससे टाइप की बेहतर जांच करने में मदद मिलेगी. - जेनरिक टाइप के साथ काम करने के लिए, जेनरिक फ़ंक्शन और मेथड बनाएं. उदाहरण के लिए:
fun <T: WaterSupply> isWaterClean(aquarium: Aquarium<T>) { ... }
- किसी क्लास में मुख्य फ़ंक्शन जोड़ने के लिए, जेनरिक एक्सटेंशन फ़ंक्शन का इस्तेमाल करें.
- कई तरह के डेटा को हमेशा के लिए मिटाने की वजह से, कार्ड के टाइप में बदलाव करना ज़रूरी होता है. सामान्य टाइप से अलग किए गए टाइप, लेकिन रनटाइम में दिखते हैं.
- आपका कोड ठीक से चल रहा है या नहीं, इसकी पुष्टि करने के लिए
check()
फ़ंक्शन इस्तेमाल करें. उदाहरण के लिए:check(!waterSupply.needsProcessing) { "water supply needs processing first" }
Kotlin दस्तावेज़
अगर आपको इस कोर्स के किसी विषय के बारे में ज़्यादा जानकारी चाहिए या आपको कोई समस्या आती है, तो आप https://kotlinlang.org से शुरुआत कर सकते हैं.
Kotlin ट्यूटोरियल
https://try.kotlinlang.org वेबसाइट पर, Kotlin कोन्स नाम के रिच ट्यूटोरियल शामिल हैं, जो वेब पर आधारित अनुवादक है. साथ ही, इसमें रेफ़रंस दस्तावेज़ का पूरा सेट भी शामिल है, जिसमें उदाहरण भी दिए गए हैं.
Udcity कोर्स
इस विषय पर Udacity कोर्स देखने के लिए, प्रोग्रामर के लिए Kotlin बूटकैंप देखें.
IntelliJ IDEA
JetBrains वेबसाइट पर, InliJ IDEA के दस्तावेज़ देखे जा सकते हैं.
इस सेक्शन में उन छात्र-छात्राओं के लिए गृहकार्य की असाइनमेंट की सूची दी गई है जो इस कोडलैब के ज़रिए एक शिक्षक की देखरेख में कोर्स में काम कर रहे हैं. यह क्रिएटर का काम #33 पर निर्भर करता है:
- अगर ज़रूरी हो, तो होमवर्क असाइन करें.
- छात्र-छात्राओं को होमवर्क के असाइनमेंट सबमिट करने के तरीके के बारे में बताएं.
- होमवर्क असाइनमेंट को ग्रेड दें.
शिक्षक इन सुझावों का इस्तेमाल जितनी चाहें उतनी कम या ज़्यादा कर सकते हैं. साथ ही, उन्हें अपने हिसाब से कोई भी होमवर्क असाइन करना चाहिए.
अगर आप इस कोडलैब के ज़रिए खुद काम कर रहे हैं, तो बेझिझक इन होमवर्क असाइनमेंट का इस्तेमाल करें.
इन सवालों का जवाब दें सवालों
पहला सवाल
जेनरिक टाइप का नाम रखने के लिए, इनमें से कौनसा तरीका सबसे सही है?
▢ <Gen>
▢ <Generic>
▢ <T>
▢ <X>
दूसरा सवाल
सामान्य टाइप के लिए पाबंदी पर लागू होता है:
सामान्य प्रतिबंध
▢ सामान्य कंस्ट्रेंट
▢ गड़बड़ी
सामान्य टाइप की सीमा
तीसरा सवाल
बदले गए तरीके:
▢ किसी ऑब्जेक्ट के वास्तविक निष्पादन प्रभाव की गणना की गई है.
▢ इस कक्षा के लिए, प्रतिबंधित एंट्री इंडेक्स सेट किया गया है.
▢ सामान्य प्रकार का पैरामीटर असल टाइप में बनाया गया है.
▢दूरी की गड़बड़ी का संकेत ट्रिगर हुआ है.
अगले लेसन पर जाएं:
कोर्स के बारे में खास जानकारी पाने के लिए, दूसरे कोडलैब के लिंक के साथ-साथ, &kot;Kotlin बूटकैंपर के लिए प्रोग्राम: कोर्स में आपका स्वागत है.