बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala · पाठ

वैरिएंस: सहवैरिएंस और प्रतिवैरिएंस

जेनेरिक प्रकारों में उपप्रकार संबंधों को सही ढंग से संभालने के लिए सहवैरिएंस और प्रतिवैरिएंस में दक्षता प्राप्त करें।

पाठ 2, कुल 3 में से11 चरण

वैरिएंस: सहवैरिएंस और प्रतिवैरिएंस, CoddyKit पर बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala का एक निःशुल्क पाठ है। यह 3 में से 2वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala पाठ्यक्रम में कुल 3 पाठ शामिल हैं।

टाइप वैरिएंस क्या है

स्काला में, जब आपके पास टाइप का कोई पदानुक्रम हो (जैसे Cat, Animal का उपप्रकार है), तो जेनेरिक प्रकार किस तरह व्यवहार करते हैं?

क्या List[Cat], List[Animal] का उपप्रकार माना जाता है? डिफ़ॉल्ट रूप से हमेशा नहीं!

टाइप वैरिएंस हमें यह निर्धारित करने देती है कि जेनेरिक प्रकारों के लिए उपप्रकार संबंध किस तरह बनाए रखे जाएँ या उलटे जाएँ। लचीला और टाइप-सुरक्षित कोड लिखने के लिए यह बहुत महत्वपूर्ण है।

कोवेरिएंस: 'Producer' प्रकार (+T)

कोवेरिएंस को टाइप पैरामीटर के पहले + लगाकर दर्शाया जाता है (जैसे trait Box[+T])।

  • यदि A, B का उपप्रकार है, तो Box[A], Box[B] का उपप्रकार बन जाता है।
  • कोवेरिएंट प्रकारों को T के 'उत्पादक' समझें। वे केवल आउटपुट स्थानों में दिखाई दे सकते हैं, जैसे मेथड के रिटर्न प्रकार।
  • इसका अर्थ है कि जहाँ Box[Animal] अपेक्षित हो, वहाँ Box[Cat] दिया जा सकता है, क्योंकि वह अधिक विशिष्ट चीज़ उत्पन्न करता है (और Cat, Animal है)।

क्रियान्वित कोवेरिएंस

कोवेरिएंट Producer ट्रेट के इस उदाहरण को चलाकर देखें:

class Animal
class Cat extends Animal

trait Producer[+T] {
  def produce: T // Output position
}

class CatProducer extends Producer[Cat] {
  def produce: Cat = new Cat
}

object Main {
  def main(args: Array[String]): Unit = {
    val catProducer: Producer[Cat] = new CatProducer
    // Because Producer is covariant, Producer[Cat] is a subtype of Producer[Animal]
    val animalProducer: Producer[Animal] = catProducer 
    println("Assigned CatProducer to AnimalProducer.")
    println(s"Produced: ${animalProducer.produce.getClass.getSimpleName}")
  }
}

कोवेरिएंस का उपयोग कब करें

कोवेरिएंस तब सुरक्षित होती है जब आपका जेनेरिक प्रकार केवल T प्रकार के मान 'उत्पन्न' करता हो या T को कभी आर्ग्युमेंट के रूप में स्वीकार न करता हो।

  • List[+T] जैसे अपरिवर्तनीय संग्रह इसका प्रमुख उदाहरण हैं। आप List[Cat] को List[Animal] की तरह मान सकते हैं, क्योंकि उसमें से आप केवल Animal या उसके उपप्रकारों को 'पढ़ते' हैं।
  • यदि उसका प्रकार List[Animal] हो, तो आप List[Cat] में कोई भी मनमाना Animal नहीं जोड़ सकते। इससे टाइप सुरक्षा बनी रहती है।

कॉन्ट्रावेरिएंस: 'Consumer' प्रकार (-T)

कॉन्ट्रावेरिएंस को टाइप पैरामीटर के पहले - लगाकर दर्शाया जाता है (जैसे trait Consumer[-T])।

  • यदि A, B का उपप्रकार है, तो Consumer[B], Consumer[A] का उपप्रकार बन जाता है।
  • कॉन्ट्रावेरिएंट प्रकारों को T के 'उपभोक्ता' समझें। वे केवल इनपुट स्थानों में दिखाई दे सकते हैं, जैसे मेथड के पैरामीटर प्रकार।
  • इसका अर्थ है कि जहाँ Consumer[Cat] अपेक्षित हो, वहाँ Consumer[Animal] दिया जा सकता है, क्योंकि वह अधिक सामान्य चीज़ को 'उपभोग' करता है (वह किसी भी Animal, जिसमें Cat भी शामिल है, को संभाल सकता है)।

क्रियान्वित कॉन्ट्रावेरिएंस

कॉन्ट्रावेरिएंट Consumer ट्रेट के इस उदाहरण को चलाकर देखें:

class Animal
class Cat extends Animal

trait Consumer[-T] {
  def consume(item: T): Unit // Input position
}

class AnimalConsumer extends Consumer[Animal] {
  def consume(item: Animal): Unit = {
    println(s"Consumed an animal: ${item.getClass.getSimpleName}")
  }
}

object Main {
  def main(args: Array[String]): Unit = {
    val animalConsumer: Consumer[Animal] = new AnimalConsumer
    // Because Consumer is contravariant, Consumer[Animal] is a subtype of Consumer[Cat]
    val catConsumer: Consumer[Cat] = animalConsumer 
    catConsumer.consume(new Cat)
    println("Assigned AnimalConsumer to CatConsumer.")
  }
}

कॉन्ट्रावेरिएंस का उपयोग कब करें

कॉन्ट्रावेरिएंस तब सुरक्षित होती है जब आपका जेनेरिक प्रकार केवल T प्रकार के मानों को 'उपभोग' करता हो या कभी T लौटाता न हो।

  • एक सामान्य उदाहरण फ़ंक्शन हैं, विशेष रूप से इनपुट पैरामीटर का प्रकार। यदि कोई फ़ंक्शन किसी भी Animal को संसाधित कर सकता है (Animal => Unit), तो वह निश्चित रूप से Cat को भी संसाधित कर सकता है। इसलिए (Animal => Unit), (Cat => Unit) का उपप्रकार है।
  • इससे फ़ंक्शन को आर्ग्युमेंट के रूप में पास करते समय अधिक लचीलापन मिलता है।

इनवेरिएंस: डिफ़ॉल्ट व्यवहार

यदि आप + या - निर्दिष्ट नहीं करते, तो टाइप पैरामीटर इनवेरिएंट होता है। स्काला में यही डिफ़ॉल्ट है।

  • Box[A], Box[B] का उपप्रकार तभी होता है जब A और B बिल्कुल एक ही प्रकार हों।
  • परिवर्तनीय संग्रहों (जैसे Array[T]) के लिए टाइप सुरक्षा संबंधी समस्याएँ रोकने हेतु यह अक्सर आवश्यक होता है, क्योंकि उनमें आप अलग-अलग उपप्रकारों को पढ़ और लिख दोनों सकते हैं।
class Food
class Apple extends Food

// Invariant Box
class Box[T](val item: T) {
  def getContent: T = item
}

object Main {
  def main(args: Array[String]): Unit = {
    val appleBox = new Box(new Apple)
    // The following line would cause a compile error:
    // val foodBox: Box[Food] = appleBox 
    println(s"An Apple Box contains: ${appleBox.getContent.getClass.getSimpleName}")
    println("Box[Apple] is NOT a subtype of Box[Food] (invariant).")
    println("The types must match exactly for invariant types.")
  }
}

फ़ंक्शन: कोवेरिएंट और कॉन्ट्रावेरिएंट दोनों

स्काला के फ़ंक्शन प्रकार, Function1[-A, +B], दोनों वैरिएंस प्रकारों को सुंदर ढंग से जोड़ते हैं:

  • इनपुट पैरामीटर A कॉन्ट्रावेरिएंट (-A) है। इसका अर्थ है कि अधिक सामान्य प्रकार (जैसे Animal) स्वीकार करने वाले फ़ंक्शन का उपयोग वहाँ किया जा सकता है जहाँ अधिक विशिष्ट प्रकार (जैसे Cat) स्वीकार करने वाला फ़ंक्शन अपेक्षित हो।
  • रिटर्न प्रकार B कोवेरिएंट (+B) है। इसका अर्थ है कि अधिक विशिष्ट प्रकार (जैसे Cat) लौटाने वाले फ़ंक्शन का उपयोग वहाँ किया जा सकता है जहाँ अधिक सामान्य प्रकार (जैसे Animal) लौटाने वाला फ़ंक्शन अपेक्षित हो।
class Vehicle
class Car extends Vehicle

object Main {
  def main(args: Array[String]): Unit = {
    // Contravariance for input: (Vehicle => Unit) is a subtype of (Car => Unit)
    val printVehicle: Vehicle => Unit = (v: Vehicle) => println(s"Printing vehicle: ${v.getClass.getSimpleName}")
    val printCar: Car => Unit = printVehicle // OK: A general printer can print a specific car
    printCar(new Car)

    // Covariance for output: (() => Car) is a subtype of (() => Vehicle)
    val getCar: () => Car = () => new Car
    val getVehicle: () => Vehicle = getCar // OK: A specific producer can fulfill a general request
    println(s"Got vehicle: ${getVehicle().getClass.getSimpleName}")
  }
}

त्वरित जाँच: वैरिएंस के नियम

निम्नलिखित ट्रेट पर विचार करें:

trait Handler[T] {
  def handle(item: T): Unit
}

ताकि Handler[Animal] का उपयोग वहाँ किया जा सके जहाँ Handler[Cat] अपेक्षित हो (जहाँ Cat, Animal का विस्तार करता है), T में कौन-सा वैरिएंस एनोटेशन होना चाहिए?

पुनरावलोकन: वैरिएंस में दक्षता

आपने स्काला में वैरिएंस में दक्षता हासिल कर ली है! आइए जल्दी से दोहरा लें:

  • कोवेरिएंस (+T): Container[Subtype] को Container[Supertype] का उपप्रकार बनने देती है। यह उन 'उत्पादक' प्रकारों के लिए उपयोगी है जो केवल T लौटाते हैं।
  • कॉन्ट्रावेरिएंस (-T): Container[Supertype] को Container[Subtype] का उपप्रकार बनने देती है। यह उन 'उपभोक्ता' प्रकारों के लिए उपयोगी है जो केवल T को इनपुट के रूप में स्वीकार करते हैं।
  • इनवेरिएंस: यह डिफ़ॉल्ट है। प्रकारों का बिल्कुल समान होना आवश्यक है।

वैरिएंस को समझने से आपको स्काला में अधिक लचीला और टाइप-सुरक्षित जेनेरिक कोड बनाने में सहायता मिलती है!

शुरुआत निःशुल्क

एआई शिक्षक के साथ Scala सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
39
पाठ
143

अक्सर पूछे जाने वाले प्रश्न

क्या “वैरिएंस: सहवैरिएंस और प्रतिवैरिएंस” पाठ निःशुल्क है?

हाँ—“वैरिएंस: सहवैरिएंस और प्रतिवैरिएंस” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala पाठ्यक्रम में कुल 3 पाठ शामिल हैं।

“वैरिएंस: सहवैरिएंस और प्रतिवैरिएंस” में मैं क्या सीखूँगा?

जेनेरिक प्रकारों में उपप्रकार संबंधों को सही ढंग से संभालने के लिए सहवैरिएंस और प्रतिवैरिएंस में दक्षता प्राप्त करें। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 3 में से 2वाँ पाठ है।

“वैरिएंस: सहवैरिएंस और प्रतिवैरिएंस” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. जेनेरिक और प्रकार पैरामीटर
  2. वैरिएंस: सहवैरिएंस और प्रतिवैरिएंस
  3. प्रकार क्लास और इम्प्लिसिट
← बैकएंड इंजीनियरिंग और कार्यात्मक प्रोग्रामिंग के लिए Scala पर वापस जाएँ