प्रोग्रामर के लिए Kotlin Bootcamp 3: फ़ंक्शन

यह कोडलैब, प्रोग्रामर के लिए Kotlin बूटकैंप कोर्स का हिस्सा है. अगर कोडलैब को क्रम से पूरा किया जाता है, तो आपको इस कोर्स से सबसे ज़्यादा फ़ायदा मिलेगा. अपनी जानकारी के हिसाब से, कुछ सेक्शन को सरसरी तौर पर पढ़ा जा सकता है. यह कोर्स उन प्रोग्रामर के लिए है जिन्हें ऑब्जेक्ट ओरिएंटेड लैंग्वेज के बारे में जानकारी है और जो Kotlin सीखना चाहते हैं.

परिचय

इस कोडलैब में, Kotlin प्रोग्राम बनाया जाता है. साथ ही, Kotlin में फ़ंक्शन के बारे में जाना जाता है. इनमें पैरामीटर के लिए डिफ़ॉल्ट वैल्यू, फ़िल्टर, लैम्ब्डा, और कॉम्पैक्ट फ़ंक्शन शामिल हैं.

इस कोर्स में, एक सैंपल ऐप्लिकेशन बनाने के बजाय, अलग-अलग विषयों पर जानकारी दी गई है. हालांकि, ये विषय एक-दूसरे से जुड़े हुए हैं, लेकिन इन्हें इस तरह से डिज़ाइन किया गया है कि आप अपनी ज़रूरत के हिसाब से किसी भी विषय को पढ़ सकें. इन सभी उदाहरणों को एक साथ दिखाने के लिए, इनमें ऐक्वेरियम की थीम का इस्तेमाल किया गया है. अगर आपको एक्वेरियम की पूरी कहानी देखनी है, तो Udacity पर प्रोग्रामर के लिए Kotlin बूटकैंप कोर्स देखें.

आपको पहले से क्या पता होना चाहिए

  • मॉडर्न, ऑब्जेक्ट-ओरिएंटेड, स्टैटिक टाइप वाली प्रोग्रामिंग भाषा की बुनियादी बातें
  • कम से कम एक भाषा में क्लास, तरीके, और अपवाद हैंडलिंग के साथ प्रोग्राम करने का तरीका
  • IntelliJ IDEA में Kotlin के REPL (Read-Eval-Print Loop) का इस्तेमाल करने का तरीका
  • Kotlin की बुनियादी बातें, जैसे कि टाइप, ऑपरेटर, और लूप

यह कोडलैब, उन प्रोग्रामर के लिए है जिन्हें ऑब्जेक्ट ओरिएंटेड लैंग्वेज के बारे में जानकारी है और वे Kotlin के बारे में ज़्यादा जानना चाहते हैं.

आपको क्या सीखने को मिलेगा

  • IntelliJ IDEA में, main() फ़ंक्शन और आर्ग्युमेंट की मदद से प्रोग्राम बनाने का तरीका
  • डिफ़ॉल्ट वैल्यू और कॉम्पैक्ट फ़ंक्शन का इस्तेमाल कैसे करें
  • सूचियों के लिए फ़िल्टर कैसे लागू करें
  • बेसिक लैम्ब्डा और हाई-ऑर्डर फ़ंक्शन बनाने का तरीका

आपको क्या करना होगा

  • कुछ कोड आज़माने के लिए, REPL का इस्तेमाल करें.
  • IntelliJ IDEA का इस्तेमाल करके, Kotlin के बुनियादी प्रोग्राम बनाएं.

इस टास्क में, आपको Kotlin प्रोग्राम बनाना है. साथ ही, main() फ़ंक्शन के बारे में जानना है. इसके अलावा, आपको यह भी सीखना है कि कमांड लाइन से किसी प्रोग्राम में आर्ग्युमेंट कैसे पास किए जाते हैं.

आपको शायद याद हो कि आपने पिछले कोडलैब में REPL में printHello() फ़ंक्शन डाला था:

fun printHello() {
    println ("Hello World")
}

printHello()
⇒ Hello World

आपने फ़ंक्शन का नाम और fun कीवर्ड का इस्तेमाल करके, फ़ंक्शन के बारे में बताया है. अन्य प्रोग्रामिंग भाषाओं की तरह, ब्रैकेट () किसी भी तरह के फ़ंक्शन आर्ग्युमेंट के लिए होते हैं. कर्ली ब्रैकेट {} फ़ंक्शन के लिए कोड फ़्रेम करते हैं. इस फ़ंक्शन के लिए कोई रिटर्न टाइप नहीं है, क्योंकि इससे कोई रिटर्न नहीं आता.

पहला चरण: Kotlin फ़ाइल बनाना

  1. IntelliJ IDEA खोलें.
  2. IntelliJ IDEA में बाईं ओर मौजूद प्रोजेक्ट पैनल में, आपके प्रोजेक्ट की फ़ाइलों और फ़ोल्डर की सूची दिखती है. Hello Kotlin में जाकर, src फ़ोल्डर ढूंढें और उस पर राइट क्लिक करें. (आपके पास पिछले कोडलैब से Hello Kotlin प्रोजेक्ट पहले से ही होना चाहिए.)
  3. नई > Kotlin फ़ाइल / क्लास चुनें.
  4. टाइप को फ़ाइल के तौर पर सेव करें और फ़ाइल का नाम Hello रखें.
  5. ठीक है पर क्लिक करें.

अब src फ़ोल्डर में Hello.kt नाम की फ़ाइल मौजूद है.

दूसरा चरण: कोड जोड़ना और प्रोग्राम चलाना

  1. दूसरी लैंग्वेज के साथ, Kotlin main() फ़ंक्शन प्रोग्राम चलाने के लिए एंट्री पॉइंट के बारे में बताता है. कोई भी कमांड लाइन आर्ग्युमेंट, स्ट्रिंग की श्रेणी के रूप में पास होते हैं.

    Hello.kt फ़ाइल में, यहां दिया गया कोड टाइप करें या चिपकाएं:
fun main(args: Array<String>) {
    println("Hello, world!")
}

आपके पहले के printHello() फ़ंक्शन की तरह, इस फ़ंक्शन में कोई भी return स्टेटमेंट नहीं है. Kotlin में हर फ़ंक्शन कुछ रिटर्न ज़रूर करता है. चाहे कुछ भी साफ़ तौर पर बताया न गया हो. इसलिए, इस तरह का main() फ़ंक्शन, kotlin.Unit टाइप की वैल्यू दिखाता है. यह Kotlin का तरीका है, यह बताने का कि कोई वैल्यू नहीं है.

  1. प्रोग्राम चलाने के लिए, main() फ़ंक्शन की बाईं ओर मौजूद हरे त्रिकोण पर क्लिक करें. मेन्यू से, Run 'HelloKt' को चुनें.
  2. IntelliJ IDEA, प्रोग्राम को कंपाइल करता है और उसे चलाता है. नतीजे, सबसे नीचे मौजूद लॉग पैनल में दिखते हैं. जैसा कि यहां दिखाया गया है.

तीसरा चरण: आर्ग्युमेंट को main() में पास करें

कमांड लाइन के बजाय, IntelliJ IDEA से प्रोग्राम को चलाने पर, आपको प्रोग्राम के बारे में किसी भी आर्ग्युमेंट को कुछ अलग ढंग से बताना पड़ेगा.

  1. चलाएं > कॉन्फ़िगरेशन में बदलाव करें को चुनें. रन/डीबग कॉन्फ़िगरेशन विंडो खुलती है.
  2. प्रोग्राम के आर्ग्युमेंट फ़ील्ड में Kotlin! टाइप करें.
  3. ठीक है पर क्लिक करें.

चौथा चरण: स्ट्रिंग टेंप्लेट का इस्तेमाल करने के लिए कोड में बदलाव करना

स्ट्रिंग टेंप्लेट, किसी स्ट्रिंग में वैरिएबल या एक्सप्रेशन डालता है. साथ ही, $ यह तय करता है कि स्ट्रिंग का कौन-सा हिस्सा वैरिएबल या एक्सप्रेशन होगा. अगर कोई एक्सप्रेशन है, तो उसे कर्ली ब्रैकेट {} में रखा जाता है.

  1. Hello.kt में, प्रोग्राम में पास किए गए पहले आर्ग्युमेंट, args[0] का इस्तेमाल करने के लिए, अभिवादन के मैसेज को बदलें. "world" के बजाय args[0] का इस्तेमाल करें.
fun main(args: Array<String>) {
    println("Hello, ${args[0]}")
}
  1. प्रोग्राम को चलाएं. आउटपुट में, आपके दिए गए आर्ग्युमेंट शामिल होंगे.
⇒ Hello, Kotlin!

इस टास्क में, आपको यह जानकारी मिलेगी कि Kotlin में करीब-करीब हर चीज़ की वैल्यू क्यों होती है और यह क्यों फ़ायदेमंद है.

कुछ अन्य लैंग्वेज में स्टेटमेंट होते हैं. ये कोड की ऐसी लाइनें होती हैं जिनकी कोई वैल्यू नहीं होती. Kotlin में, करीब-करीब हर चीज़ का कोई एक्सप्रेशन होता है और हर चीज़ की वैल्यू होती है—चाहे यह वैल्यू kotlin.Unit ही हो.

  1. Hello.kt में, main() में कोड लिखें, ताकि println() को isUnit नाम के वैरिएबल को असाइन किया जा सके और उसे प्रिंट किया जा सके. (println() कोई वैल्यू नहीं दिखाता है, इसलिए यह kotlin.Unit दिखाता है.)
// Will assign kotlin.Unit
val isUnit = println("This is an expression")
println(isUnit)
  1. प्रोग्राम चलाएं. पहले println() से, स्ट्रिंग "This is an expression" प्रिंट होती है. दूसरा println(), पहले println() स्टेटमेंट की वैल्यू को प्रिंट करता है. यानी, kotlin.Unit.
⇒ This is an expression
kotlin.Unit
  1. temperature नाम के val का एलान करें और इसे 10 पर सेट करें.
  2. इसके बाद, isHot नाम की एक और val का एलान करें और if/else स्टेटमेंट की रिटर्न वैल्यू को isHot में असाइन करें. ऐसा नीचे दिए गए कोड में दिखाया गया है. यह एक एक्सप्रेशन है. इसलिए, if एक्सप्रेशन की वैल्यू का तुरंत इस्तेमाल किया जा सकता है.
val temperature = 10
val isHot = if (temperature > 50) true else false
println(isHot)
⇒ false
  1. स्ट्रिंग टेंप्लेट में एक्सप्रेशन की वैल्यू का इस्तेमाल करें. मछली के तापमान की जांच करने के लिए कुछ कोड जोड़ें, ताकि यह पता चल सके कि मछली सुरक्षित है या उसका तापमान बहुत ज़्यादा है. इसके बाद, अपना प्रोग्राम चलाएं.
val temperature = 10
val message = "The water temperature is ${ if (temperature > 50) "too warm" else "OK" }."
println(message)
⇒ The water temperature is OK.

इस टास्क में, आपको Kotlin में फ़ंक्शन के बारे में ज़्यादा जानकारी मिलेगी. साथ ही, when कंडीशनल एक्सप्रेशन के बारे में भी ज़्यादा जानकारी मिलेगी.

पहला चरण: कुछ फ़ंक्शन बनाना

इस चरण में, आपको सीखी गई कुछ बातों को एक साथ रखना है और अलग-अलग तरह के फ़ंक्शन बनाने हैं. Hello.kt के कॉन्टेंट को इस नए कोड से बदला जा सकता है.

  1. feedTheFish() नाम का एक फ़ंक्शन लिखें, जो हफ़्ते के किसी दिन को रैंडम तरीके से पाने के लिए randomDay() को कॉल करता है. उस दिन मछली को खाने के लिए food प्रिंट करने के लिए, स्ट्रिंग टेंप्लेट का इस्तेमाल करें. फ़िलहाल, मछलियां हर दिन एक जैसा खाना खाती हैं.
fun feedTheFish() {
    val day = randomDay()
    val food = "pellets"
    println ("Today is $day and the fish eat $food")
}

fun main(args: Array<String>) {
    feedTheFish()
}
  1. ऐरे से कोई दिन चुनने और उसे वापस लाने के लिए, randomDay() फ़ंक्शन लिखें.

nextInt() फ़ंक्शन में पूर्णांक की सीमा होती है. यह Random() से 0 से 6 तक की संख्या को सीमित करता है, ताकि यह week ऐरे से मेल खा सके.

fun randomDay() : String {
    val week = arrayOf ("Monday", "Tuesday", "Wednesday", "Thursday",
            "Friday", "Saturday", "Sunday")
    return week[Random().nextInt(week.size)]
}
  1. Random() और nextInt() फ़ंक्शन, java.util.* में तय किए गए हैं. फ़ाइल में सबसे ऊपर, ज़रूरी इंपोर्ट जोड़ें:
import java.util.*    // required import
  1. अपना प्रोग्राम चलाएं और आउटपुट देखें.
⇒ Today is Tuesday and the fish eat pellets

दूसरा चरण: when एक्सप्रेशन का इस्तेमाल करना

इसे और बेहतर बनाने के लिए, कोड में बदलाव करें. इसके लिए, when एक्सप्रेशन का इस्तेमाल करके, अलग-अलग दिनों के लिए अलग-अलग खाना चुनें. when स्टेटमेंट, अन्य प्रोग्रामिंग भाषाओं में switch स्टेटमेंट की तरह होता है. हालांकि, when स्टेटमेंट हर ब्रांच के आखिर में अपने-आप ब्रेक हो जाता है. यह भी पक्का करता है कि अगर किसी enum की जांच की जा रही है, तो आपका कोड सभी ब्रांच को कवर करता हो.

  1. Hello.kt में, fishFood() नाम का एक फ़ंक्शन जोड़ें. यह फ़ंक्शन, दिन को String के तौर पर लेता है और दिन के हिसाब से मछली के खाने को String के तौर पर दिखाता है. when() का इस्तेमाल करें, ताकि हर दिन मछली को एक खास तरह का खाना मिल सके. अलग-अलग आउटपुट देखने के लिए, अपने प्रोग्राम को कुछ बार चलाएं.
fun fishFood (day : String) : String {
    var food = ""
    when (day) {
        "Monday" -> food = "flakes"
        "Tuesday" -> food = "pellets"
        "Wednesday" -> food = "redworms"
        "Thursday" -> food = "granules"
        "Friday" -> food = "mosquitoes"
        "Saturday" -> food = "lettuce"
        "Sunday" -> food = "plankton"
    }
    return food
}

fun feedTheFish() {
    val day = randomDay()
    val food = fishFood(day)

    println ("Today is $day and the fish eat $food")
}
⇒ Today is Thursday and the fish eat granules
  1. else का इस्तेमाल करके, when एक्सप्रेशन में डिफ़ॉल्ट ब्रांच जोड़ें. जांच के लिए, Tuesday और Saturday ब्रांच हटाएं, ताकि यह पक्का किया जा सके कि आपके प्रोग्राम में डिफ़ॉल्ट वैल्यू का इस्तेमाल किया गया है.

    डिफ़ॉल्ट ब्रांच होने से यह पक्का होता है कि food को वैल्यू मिल गई है. इसलिए, इसे अब शुरू करने की ज़रूरत नहीं है. अब कोड में food को सिर्फ़ एक बार स्ट्रिंग असाइन की जाती है. इसलिए, var के बजाय val का इस्तेमाल करके food को एलान किया जा सकता है.
fun fishFood (day : String) : String {
    val food : String
    when (day) {
        "Monday" -> food = "flakes"
        "Wednesday" -> food = "redworms"
        "Thursday" -> food = "granules"
        "Friday" -> food = "mosquitoes"
        "Sunday" -> food = "plankton"
        else -> food = "nothing"
    }
    return food
}
  1. हर एक्सप्रेशन की एक वैल्यू होती है. इसलिए, इस कोड को थोड़ा और छोटा किया जा सकता है. when एक्सप्रेशन की वैल्यू सीधे तौर पर दिखाएं और food वैरिएबल को हटाएं. when एक्सप्रेशन की वैल्यू, उस ब्रांच के आखिरी एक्सप्रेशन की वैल्यू होती है जिसने शर्त पूरी की है.
fun fishFood (day : String) : String {
    return when (day) {
        "Monday" -> "flakes"
        "Wednesday" -> "redworms"
        "Thursday" -> "granules"
        "Friday" -> "mosquitoes"
        "Sunday" -> "plankton"
        else -> "nothing"
    }
}

आपके प्रोग्राम का फ़ाइनल वर्शन, नीचे दिए गए कोड की तरह दिखता है.

import java.util.*    // required import

fun randomDay() : String {
    val week = arrayOf ("Monday", "Tuesday", "Wednesday", "Thursday",
        "Friday", "Saturday", "Sunday")
    return week[Random().nextInt(week.size)]
}

fun fishFood (day : String) : String {
    return when (day) {
        "Monday" -> "flakes"
        "Wednesday" -> "redworms"
        "Thursday" -> "granules"
        "Friday" -> "mosquitoes"
        "Sunday" -> "plankton"
        else -> "nothing"
    }
}

fun feedTheFish() {
    val day = randomDay()
    val food = fishFood(day)
    println ("Today is $day and the fish eat $food")
}

fun main(args: Array<String>) {
    feedTheFish()
}

इस टास्क में, आपको फ़ंक्शन और तरीकों के लिए डिफ़ॉल्ट वैल्यू के बारे में जानकारी मिलती है. आपको कॉम्पैक्ट फ़ंक्शन के बारे में भी जानकारी मिलती है. इनकी मदद से, कोड को छोटा और पढ़ने लायक बनाया जा सकता है. साथ ही, टेस्टिंग के लिए कोड पाथ की संख्या को कम किया जा सकता है. कॉम्पैक्ट फ़ंक्शन को एक एक्सप्रेशन वाले फ़ंक्शन भी कहा जाता है.

पहला चरण: किसी पैरामीटर के लिए डिफ़ॉल्ट वैल्यू बनाना

Kotlin में, पैरामीटर के नाम से आर्ग्युमेंट पास किए जा सकते हैं. पैरामीटर के लिए डिफ़ॉल्ट वैल्यू भी तय की जा सकती हैं: अगर कॉलर कोई आर्ग्युमेंट नहीं देता है, तो डिफ़ॉल्ट वैल्यू का इस्तेमाल किया जाता है. बाद में, जब आपको तरीके (मेंबर फ़ंक्शन) लिखने होते हैं, तो इसका मतलब है कि आपको एक ही तरीके के कई ओवरलोड वर्शन लिखने की ज़रूरत नहीं है.

  1. Hello.kt में, String पैरामीटर के साथ swim() फ़ंक्शन लिखें. इस पैरामीटर का नाम speed है और इससे मछली की स्पीड को प्रिंट किया जाता है. speed पैरामीटर की डिफ़ॉल्ट वैल्यू "fast" होती है.
fun swim(speed: String = "fast") {
   println("swimming $speed")
}
  1. main() फ़ंक्शन से, swim() फ़ंक्शन को तीन तरह से कॉल करें. डिफ़ॉल्ट का इस्तेमाल करके फ़ंक्शन को कॉल करें. इसके बाद, फ़ंक्शन को कॉल करें और बिना नाम के speed पैरामीटर को पास करें. इसके बाद, speed पैरामीटर को नाम देकर फ़ंक्शन को कॉल करें.
swim()   // uses default speed
swim("slow")   // positional argument
swim(speed="turtle-like")   // named parameter
⇒ swimming fast
swimming slow
swimming turtle-like

दूसरा चरण: ज़रूरी पैरामीटर जोड़ना

अगर किसी पैरामीटर के लिए कोई भी डिफ़ॉल्ट तय नहीं है, तो उससे जुड़ा आर्ग्युमेंट हमेशा पास करना होगा.

  1. Hello.kt में, एक shouldChangeWater() फ़ंक्शन लिखें. यह तीन पैरामीटर लेता है: day, temperature, और dirty लेवल. अगर पानी बदलना है, तो फ़ंक्शन true दिखाता है. ऐसा तब होता है, जब रविवार हो, तापमान बहुत ज़्यादा हो या पानी बहुत गंदा हो. हफ़्ते का दिन ज़रूरी है, लेकिन डिफ़ॉल्ट तापमान 22 है और डिफ़ॉल्ट गंदा लेवल 20 है.

    बिना किसी तर्क के when एक्सप्रेशन का इस्तेमाल करें. Kotlin में यह if/else if की एक सीरीज़ के तौर पर काम करता है.
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20): Boolean {
    return when {
        temperature > 30 -> true
        dirty > 30 -> true
        day == "Sunday" ->  true
        else -> false
    }
}
  1. feedTheFish() से shouldChangeWater() को कॉल करो और दिन बताओ. day पैरामीटर की कोई डिफ़ॉल्ट वैल्यू नहीं होती. इसलिए, आपको एक आर्ग्युमेंट तय करना होगा. shouldChangeWater() के अन्य दो पैरामीटर की डिफ़ॉल्ट वैल्यू होती हैं. इसलिए, आपको उनके लिए आर्ग्युमेंट पास करने की ज़रूरत नहीं है.
fun feedTheFish() {
    val day = randomDay()
    val food = fishFood(day)
    println ("Today is $day and the fish eat $food")
    println("Change water: ${shouldChangeWater(day)}")
}
=> Today is Thursday and the fish eat granules
Change water: false

तीसरा चरण: कॉम्पैक्ट फ़ंक्शन बनाना

पिछले चरण में लिखे गए when एक्सप्रेशन में, कम कोड में ज़्यादा लॉजिक शामिल किया गया है. अगर आपको इस कोड को थोड़ा और आसान बनाना है या जांच करने की शर्तें ज़्यादा मुश्किल हैं, तो अच्छी तरह से नाम दिए गए कुछ लोकल वैरिएबल का इस्तेमाल किया जा सकता है. हालांकि, Kotlin में इसे कॉम्पैक्ट फ़ंक्शन की मदद से किया जाता है.

कॉम्पैक्ट फ़ंक्शन या एक एक्सप्रेशन वाले फ़ंक्शन, Kotlin में एक सामान्य पैटर्न है. जब कोई फ़ंक्शन, किसी एक एक्सप्रेशन के नतीजे दिखाता है, तब फ़ंक्शन के मुख्य हिस्से को = सिंबल के बाद बताया जा सकता है. साथ ही, कर्ली ब्रैकेट {} और return को हटाया जा सकता है.

  1. Hello.kt में, शर्तों की जांच करने के लिए कॉम्पैक्ट फ़ंक्शन जोड़ें.
fun isTooHot(temperature: Int) = temperature > 30

fun isDirty(dirty: Int) = dirty > 30

fun isSunday(day: String) = day == "Sunday"
  1. नए फ़ंक्शन को कॉल करने के लिए, shouldChangeWater() को बदलें.
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20): Boolean {
    return when {
        isTooHot(temperature) -> true
        isDirty(dirty) -> true
        isSunday(day) -> true
        else  -> false
    }
}
  1. प्रोग्राम चलाएं. println() के साथ shouldChangeWater() का आउटपुट, कॉम्पैक्ट फ़ंक्शन का इस्तेमाल शुरू करने से पहले जैसा था वैसा ही होना चाहिए.

डिफ़ॉल्ट वैल्यू

किसी पैरामीटर की डिफ़ॉल्ट वैल्यू, वैल्यू के तौर पर नहीं होनी चाहिए. यह कोई दूसरा फ़ंक्शन भी हो सकता है. यहां दिए गए सैंपल में इसका कुछ हिस्सा दिखाया गया है:

fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = getDirtySensorReading()): Boolean {
    ...

इस टास्क में, आपको Kotlin में फ़िल्टर के बारे में कुछ जानकारी मिलेगी. कुछ स्थितियों के आधार पर बनी सूची का कुछ हिस्सा देखने के लिए, फ़िल्टर एक आसान तरीका है.

पहला चरण: फ़िल्टर बनाना

  1. Hello.kt में, सबसे ऊपर listOf() के साथ, ऐक्वेरियम की सजावट के सामान की सूची तय करें. Hello.kt फ़ाइल के कॉन्टेंट को बदला जा सकता है.
val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")
  1. सिर्फ़ 'प' वर्ण से शुरू होने वाले डेकोरेशन को प्रिंट करने के लिए, एक लाइन वाला नया main() फ़ंक्शन बनाएं. फ़िल्टर करने के पैमाने का कोड कर्ली ब्रैकेट {} में होता है. साथ ही, it का मतलब है कि फ़िल्टर लूप से हर आइटम की जांच की जाती है. अगर एक्सप्रेशन true दिखाता है, तो आइटम शामिल किया जाता है.
fun main() {
    println( decorations.filter {it[0] == 'p'})
}
  1. प्रोग्राम चलाने पर, आपको Run विंडो में यह आउटपुट दिखेगा:
⇒ [pagoda, plastic plant]

दूसरा चरण: ईगर और लेज़ी फ़िल्टर की तुलना करना

अगर आपको अन्य भाषाओं में फ़िल्टर के बारे में जानकारी है, तो आपको यह जानना होगा कि Kotlin में फ़िल्टर eager हैं या lazy. क्या नतीजे वाली सूची को तुरंत बनाया जाता है या तब, जब सूची को ऐक्सेस किया गया हो? Kotlin में, यह आपकी ज़रूरत के हिसाब से होता है. डिफ़ॉल्ट रूप से, filter ईगर होते हैं और हर बार जब फ़िल्टर का इस्तेमाल किया जाता है, तो एक लिस्ट बनती है.

लेज़ी फ़िल्टर बनाने के लिए, Sequence का इस्तेमाल करें. यह ऐसा कलेक्शन होता है जो एक समय पर सिर्फ़ एक ही आइटम को देखता है. इसकी शुरुआत शुरू से होती है और आखिर में जाकर खत्म होती है. आसानी से, यही वह एपीआई है जो लेज़ी फ़िल्टर के लिए ज़रूरी है.

  1. Hello.kt में, अपने कोड में बदलाव करके, फ़िल्टर की गई सूची को eager नाम के वैरिएबल को असाइन करें. इसके बाद, उसे प्रिंट करें.
fun main() {
    val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")

    // eager, creates a new list
    val eager = decorations.filter { it [0] == 'p' }
    println("eager: " + eager)
  1. उस कोड के नीचे, asSequence() के साथ asSequence() का इस्तेमाल करके फ़िल्टर को इवैलुएट करें.Sequence filtered वैरिएबल को क्रम असाइन करें और उसे प्रिंट करें.
   // lazy, will wait until asked to evaluate
    val filtered = decorations.asSequence().filter { it[0] == 'p' }
    println("filtered: " + filtered)

फ़िल्टर के नतीजों को Sequence के तौर पर रिटर्न करने पर, Sequence वैरिएबल नई सूची को होल्ड नहीं करता. इसके बजाय, वह इन एलिमेंट पर लागू करने के लिए, सूची एलिमेंट के Sequence को और फ़िल्टर की नॉलेज को होल्ड करेगा.filtered Sequence के एलिमेंट ऐक्सेस करने पर, फ़िल्टर लागू होता है और नतीजा आपको रिटर्न किया जाता है.

  1. क्रम को toList() के साथ List में बदलकर उसका इवैलुएशन करें. नतीजे को प्रिंट करें.
    // force evaluation of the lazy list
    val newList = filtered.toList()
    println("new list: " + newList)
  1. प्रोग्राम चलाएं और आउटपुट देखें.
⇒ eager: [pagoda, plastic plant]
filtered: kotlin.sequences.FilteringSequence@386cc1c4
new list: [pagoda, plastic plant]

Sequence और लेज़ी इवैलुएशन की प्रोसेस को विज़ुअलाइज़ करने के लिए, map() फ़ंक्शन का इस्तेमाल करें. map() फ़ंक्शन, क्रम में मौजूद हर एलिमेंट पर सामान्य बदलाव करता है.

  1. ऊपर दी गई decorations सूची का इस्तेमाल करके, map() की मदद से ऐसा बदलाव करें जिससे कुछ न हो. साथ ही, सिर्फ़ उस एलिमेंट को वापस लाएं जिसे पास किया गया था. जब भी किसी एलिमेंट को ऐक्सेस किया जाए, तब उसे दिखाने के लिए println() जोड़ें. साथ ही, सीक्वेंस को lazyMap नाम के वैरिएबल को असाइन करें.
    val lazyMap = decorations.asSequence().map {
        println("access: $it")
        it
    }
  1. lazyMap को प्रिंट करें, first() का इस्तेमाल करके lazyMap के पहले एलिमेंट को प्रिंट करें, और lazyMap को List में बदलकर प्रिंट करें.
    println("lazy: $lazyMap")
    println("-----")
    println("first: ${lazyMap.first()}")
    println("-----")
    println("all: ${lazyMap.toList()}")
  1. प्रोग्राम चलाएं और आउटपुट देखें. lazyMap को प्रिंट करने पर, सिर्फ़ Sequence का रेफ़रंस प्रिंट होता है. अंदरूनी println() को कॉल नहीं किया जाता. पहले एलिमेंट को प्रिंट करने पर, सिर्फ़ पहले एलिमेंट को ऐक्सेस किया जाता है. Sequence को List में बदलने पर, सभी एलिमेंट ऐक्सेस किए जा सकते हैं.
⇒ lazy: kotlin.sequences.TransformingSequence@5ba23b66
-----
access: rock
first: rock
-----
access: rock
access: pagoda
access: plastic plant
access: alligator
access: flowerpot
all: [rock, pagoda, plastic plant, alligator, flowerpot]
  1. Sequence लागू करने से पहले, ओरिजनल फ़िल्टर का इस्तेमाल करके नया Sequence बनाएं.map उस नतीजे को प्रिंट करें.
    val lazyMap2 = decorations.asSequence().filter {it[0] == 'p'}.map {
        println("access: $it")
        it
    }
    println("-----")
    println("filtered: ${ lazyMap2.toList() }")
  1. अपने प्रोग्राम को चलाएं और अतिरिक्त आउटपुट देखें. पहले एलिमेंट को पाने के लिए, सिर्फ़ उन एलिमेंट के लिए इनर println() को कॉल किया जाता है जिन्हें ऐक्सेस किया जाता है.
⇒
-----
access: pagoda
access: plastic plant
filtered: [pagoda, plastic plant]

इस टास्क में, आपको Kotlin में lambdas और हाई-ऑर्डर फ़ंक्शन के बारे में जानकारी मिलेगी.

Lambdas

पारंपरिक नाम वाले फ़ंक्शन के साथ ही, Kotlin में lambdas पर काम किया जा सकता है. लैम्डा एक ऐसा एक्सप्रेशन है जो फ़ंक्शन बनाता है. नाम वाले फ़ंक्शन का एलान करने के बजाय, आपने बिना नाम वाले फ़ंक्शन का एलान किया है. यह बात lambda एक्सप्रेशन को काम का बनाती है कि इसे अब डेटा के तौर पर भेजा जा सकता है. अन्य लैंग्वेज में, lambdas को पहचान छिपाने वाले फ़ंक्शन, फ़ंक्शन लिटरल या ऐसे ही मिलते-जुलते नाम से जाना जाता है.

हाई-ऑर्डर फ़ंक्शन

किसी दूसरे फ़ंक्शन में lambda पास करके, हाई-ऑर्डर फ़ंक्शन बनाया जा सकता है. पिछले टास्क में, आपने filter नाम का एक हाई-ऑर्डर फ़ंक्शन बनाया था. आपने filter को जांच करने की शर्त के तौर पर यह लैम्डा एक्सप्रेशन दिया है:
{it[0] == 'p'}

इसी तरह, map एक हाई-ऑर्डर फ़ंक्शन है. इसमें आपने जो lambda पास किया था वह ट्रांसफ़ॉर्मेशन को लागू करने के लिए था.

पहला चरण: लैंबडा के बारे में जानें

  1. नाम वाले फ़ंक्शन की तरह, lambdas के भी पैरामीटर हो सकते हैं. Lambdas के लिए, पैरामीटर (और उनके टाइप, अगर ज़रूरी हों) फ़ंक्शन ऐरो -> की बाईं ओर होते हैं. एक्ज़ीक्यूट करने के लिए कोड, फ़ंक्शन ऐरो की दाईं ओर होते हैं. वैरिएबल को lambda असाइन होने के बाद, इसे फ़ंक्शन की तरह कॉल किया जा सकता है.

    REPL (Tools > Kotlin > Kotlin REPL) का इस्तेमाल करके, इस कोड को आज़माएं:
var dirtyLevel = 20
val waterFilter = { dirty : Int -> dirty / 2}
println(waterFilter(dirtyLevel))
⇒ 10

इस उदाहरण में, लैंबडा फ़ंक्शन Int नाम का dirty लेता है और dirty / 2 दिखाता है. (क्योंकि फ़िल्टर करने से गंदगी हट जाती है.)

  1. फ़ंक्शन टाइप के लिए Kotlin सिंटैक्स, काफ़ी हद तक lambdas के लिए Kotlin सिंटैक्स से मिलता-जुलता है. फ़ंक्शन को होल्ड करने वाले वैरिएबल का एलान करने के लिए, इस सिंटैक्स का इस्तेमाल करें:
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }

कोड यह कहता है:

  • waterFilter नाम का वैरिएबल बनाएं.
  • waterFilter कोई भी ऐसा फ़ंक्शन हो सकता है जो Int को लेता हो और Int को रिटर्न करता हो.
  • लैम्डा को waterFilter पर असाइन करें.
  • यह लैम्डा, आर्ग्युमेंट dirty की वैल्यू को 2 से भाग देने पर मिलने वाली वैल्यू दिखाता है.

ध्यान दें कि अब आपको lambda आर्ग्युमेंट के टाइप को बताने की ज़रूरत नहीं है. टाइप का हिसाब टाइप अनुमान से लगाया जाता है.

दूसरा चरण: हाई-ऑर्डर फ़ंक्शन बनाना

अब तक, lambdas के उदाहरण ज़्यादातर फ़ंक्शन की तरह दिखते हैं. Lambdas की असली ताकत है उसे इस्तेमाल करके, ऐसा हाई-ऑर्डर फ़ंक्शन बनाना जहां किसी एक फ़ंक्शन का आर्ग्युमेंट, दूसरा फ़ंक्शन हो.

  1. एक हाई-ऑर्डर फ़ंक्शन लिखें. यहां एक बुनियादी उदाहरण दिया गया है. यह एक ऐसा फ़ंक्शन है जो दो आर्ग्युमेंट लेता है. पहला आर्ग्युमेंट एक पूर्णांक होता है. दूसरा आर्ग्युमेंट एक ऐसा फ़ंक्शन होता है जो पूर्णांक लेता है और पूर्णांक दिखाता है. इसे REPL में आज़माएं.
fun updateDirty(dirty: Int, operation: (Int) -> Int): Int {
   return operation(dirty)
}

कोड का मुख्य हिस्सा, उस फ़ंक्शन को कॉल करता है जो दूसरे आर्ग्युमेंट के तौर पर पास हुआ था. साथ ही, पहले आर्ग्युमेंट को पास करता है.

  1. इस फ़ंक्शन को कॉल करने के लिए, पूर्णांक और फ़ंक्शन पास करें.
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }
println(updateDirty(30, waterFilter))
⇒ 15

पास किया गया फ़ंक्शन, lambda होना ज़रूरी नहीं है. इसके बजाय, यह कोई सामान्य नाम वाला फ़ंक्शन भी हो सकता है. आर्ग्युमेंट को सामान्य फ़ंक्शन के तौर पर तय करने के लिए, :: ऑपरेटर का इस्तेमाल करें. इससे Kotlin को यह पता चलता है कि आपने फ़ंक्शन रेफ़रंस को आर्ग्युमेंट के तौर पर पास किया है, न कि फ़ंक्शन को कॉल करने की कोशिश की है.

  1. updateDirty() में, सामान्य नाम वाला फ़ंक्शन पास करके देखें.
fun increaseDirty( start: Int ) = start + 1

println(updateDirty(15, ::increaseDirty))
⇒ 16
var dirtyLevel = 19;
dirtyLevel = updateDirty(dirtyLevel) { dirtyLevel -> dirtyLevel + 23}
println(dirtyLevel)
⇒ 42
  • IntelliJ IDEA में Kotlin सोर्स फ़ाइल बनाने के लिए, Kotlin प्रोजेक्ट से शुरुआत करें.
  • IntelliJ IDEA में किसी प्रोग्राम को कंपाइल और चलाने के लिए, main() फ़ंक्शन के बगल में मौजूद हरे रंग के त्रिकोण पर क्लिक करें. आउटपुट, नीचे मौजूद लॉग विंडो में दिखता है.
  • IntelliJ IDEA में, Run > Edit Configurations में जाकर, main() फ़ंक्शन को पास करने के लिए कमांड लाइन आर्ग्युमेंट तय करें.
  • Kotlin में, करीब-करीब हर चीज़ की वैल्यू होती है. इस फ़ैक्ट का इस्तेमाल करके, अपने कोड को ज़्यादा छोटा बनाया जा सकता है. इसके लिए, if या when की वैल्यू को एक्सप्रेशन या रिटर्न वैल्यू के तौर पर इस्तेमाल करें.
  • डिफ़ॉल्ट आर्ग्युमेंट की मदद से, किसी फ़ंक्शन या तरीके के कई वर्शन इस्तेमाल करने की ज़रूरत नहीं होती. उदाहरण के लिए:
    fun swim(speed: String = "fast") { ... }
  • कॉम्पैक्ट फ़ंक्शन या एक एक्सप्रेशन वाले फ़ंक्शन, आपके कोड को और ज़्यादा पढ़ने लायक बना सकते हैं. उदाहरण के लिए:
    fun isTooHot(temperature: Int) = temperature > 30
  • आपने फ़िल्टर के बारे में कुछ बुनियादी बातें जान ली हैं. ये फ़िल्टर, लैम्डा एक्सप्रेशन का इस्तेमाल करते हैं. उदाहरण के लिए:
    val beginsWithP = decorations.filter { it [0] == 'p' }
  • लैम्डा एक्सप्रेशन एक ऐसा एक्सप्रेशन होता है जो बिना नाम वाला फ़ंक्शन बनाता है. लैम्ब्डा एक्सप्रेशन, कर्ली ब्रैकेट {} के बीच में तय किए जाते हैं.
  • हाई-ऑर्डर फ़ंक्शन में, किसी फ़ंक्शन को डेटा के तौर पर दूसरे फ़ंक्शन में पास किया जाता है. जैसे, लैम्डा एक्सप्रेशन. उदाहरण के लिए:
    dirtyLevel = updateDirty(dirtyLevel) { dirtyLevel -> dirtyLevel + 23}

इस लेसन में काफ़ी कुछ बताया गया है. खास तौर पर, अगर आपने लैम्डा के बारे में पहली बार सुना है. बाद के किसी लेसन में, Lambdas और हाई-ऑर्डर फ़ंक्शन के बारे में फिर से बताया गया है.

Kotlin का दस्तावेज़

अगर आपको इस कोर्स के किसी विषय के बारे में ज़्यादा जानकारी चाहिए या आपको कोई समस्या आ रही है, तो https://kotlinlang.org पर जाएं.

Kotlin के ट्यूटोरियल

https://try.kotlinlang.org वेबसाइट पर, Kotlin Koans नाम के रिच ट्यूटोरियल, वेब पर आधारित इंटरप्रेटर, और उदाहरणों के साथ रेफ़रंस दस्तावेज़ों का पूरा सेट शामिल है.

Udacity कोर्स

इस विषय पर Udacity का कोर्स देखने के लिए, Kotlin Bootcamp for Programmers पर जाएं.

IntelliJ IDEA

IntelliJ IDEA के लिए दस्तावेज़, JetBrains की वेबसाइट पर उपलब्ध हैं.

इस सेक्शन में, उन छात्र-छात्राओं के लिए होमवर्क असाइनमेंट की सूची दी गई है जो किसी शिक्षक के कोर्स के हिस्से के तौर पर इस कोडलैब पर काम कर रहे हैं. शिक्षक के पास ये विकल्प होते हैं:

  • अगर ज़रूरी हो, तो होमवर्क असाइन करें.
  • छात्र-छात्राओं को बताएं कि होमवर्क असाइनमेंट कैसे सबमिट किए जाते हैं.
  • होमवर्क असाइनमेंट को ग्रेड दें.

शिक्षक इन सुझावों का इस्तेमाल अपनी ज़रूरत के हिसाब से कर सकते हैं. साथ ही, वे चाहें, तो कोई दूसरा होमवर्क भी दे सकते हैं.

अगर आपको यह कोडलैब खुद से पूरा करना है, तो अपनी जानकारी की जांच करने के लिए, इन होमवर्क असाइनमेंट का इस्तेमाल करें.

इन सवालों के जवाब दें

पहला सवाल

अगर स्ट्रिंग element, उस स्ट्रिंग में मौजूद है जिस पर इसे कॉल किया गया है, तो contains(element: String) फ़ंक्शन true दिखाता है. इस कोड का आउटपुट क्या होगा?

val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")

println(decorations.filter {it.contains('p')})

[pagoda, plastic, plant]

[pagoda, plastic plant]

[pagoda, plastic plant, flowerpot]

[rock, alligator]

दूसरा सवाल

नीचे दी गई फ़ंक्शन की परिभाषा में, कौनसे पैरामीटर की ज़रूरत है?
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20, numDecorations: Int = 0): Boolean {...}

numDecorations

dirty

day

temperature

तीसरा सवाल

नाम वाले किसी सामान्य फ़ंक्शन को किसी दूसरे फ़ंक्शन में पास किया जा सकता है. हालांकि, ऐसा करने के लिए, आपको फ़ंक्शन को कॉल करने के बाद मिलने वाले नतीजे को पास नहीं करना होगा. increaseDirty( start: Int ) = start + 1 को updateDirty(dirty: Int, operation: (Int) -> Int) में कैसे पास किया जाएगा?

updateDirty(15, &increaseDirty())

updateDirty(15, increaseDirty())

updateDirty(15, ("increaseDirty()"))

updateDirty(15, ::increaseDirty)

अगले लेसन पर जाएं: 4. क्लास और ऑब्जेक्ट

कोर्स की खास जानकारी और अन्य कोडलैब के लिंक देखने के लिए, "प्रोग्रामर के लिए Kotlin बूटकैंप: कोर्स में आपका स्वागत है." लेख पढ़ें