Scala Language
टाइप वैरिएसन
खोज…
सहप्रसरण
+
प्रतीक एक प्रकार के पैरामीटर को सहसंयोजक के रूप में चिह्नित करता है - यहां हम कहते हैं कि " Producer
A
पर सहसंयोजक है":
trait Producer[+A] {
def produce: A
}
एक सहसंयोजक प्रकार के पैरामीटर को "आउटपुट" प्रकार के रूप में माना जा सकता है। A
सहसंयोजक के रूप में मार्किंग का दावा है कि Producer[X] <: Producer[Y]
प्रदान करता है कि X <: Y
। उदाहरण के लिए, एक Producer[Cat]
एक वैध Producer[Animal]
, क्योंकि सभी उत्पादित बिल्लियां भी वैध जानवर हैं।
एक सहसंयोजक प्रकार पैरामीटर कंट्रावेरेंट (इनपुट) स्थिति में प्रकट नहीं हो सकता है। निम्नलिखित उदाहरण संकलित नहीं करेंगे क्योंकि हम उस Co[Cat] <: Co[Animal]
जोर दे रहे हैं, लेकिन Co[Cat]
में def handle(a: Cat): Unit
जो किसी भी Animal
को Co[Animal]
रूप में संभाल नहीं सकती है!
trait Co[+A] {
def produce: A
def handle(a: A): Unit
}
इस प्रतिबंध से निपटने का एक तरीका यह है कि सहसंयोजी प्रकार के मापदंडों से बंधे हुए प्रकार के मापदंडों का उपयोग किया जाए। निम्नलिखित उदाहरण में, हम जानते हैं कि B
A
का एक सुपरस्क्रिप्ट है। इसलिए दिए गए Option[X] <: Option[Y]
X <: Y
लिए Option[X] <: Option[Y]
X <: Y
, हम जानते हैं कि Option[X]
का def getOrElse[B >: X](b: => B): B
, X
किसी भी सुपरस्क्रिप्ट को स्वीकार कर सकता है - जिसमें Option[Y]
द्वारा आवश्यक Y
के सुपरपाइप शामिल हैं:
trait Option[+A] {
def getOrElse[B >: A](b: => B): B
}
निश्चरता
डिफ़ॉल्ट रूप से सभी प्रकार के पैरामीटर अपरिवर्तनीय हैं - दिए गए trait A[B]
, हम कहते हैं कि " A
B
पर अपरिवर्तनीय है"। इसका मतलब यह है कि दो पैराट्रिजेशन A[Cat]
और A[Animal]
, हम इन दो प्रकारों के बीच कोई उप / सुपरक्लास संबंध नहीं मानते हैं - यह नहीं मानता है कि A[Cat] <: A[Animal]
और न ही A[Cat] >: A[Animal]
Cat
और Animal
बीच संबंध की परवाह किए बिना A[Cat] >: A[Animal]
।
वैरिएंट एनोटेशन हमें इस तरह के संबंध की घोषणा करने का एक साधन प्रदान करता है, और प्रकार के मापदंडों के उपयोग पर नियम लागू करता है ताकि संबंध वैध रहे।
contravariance
-
प्रतीक कॉन्ट्रवर्टर के रूप में एक प्रकार के पैरामीटर को चिह्नित करता है - यहां हम कहते हैं कि " Handler
A
पर कंट्रावेरिएंट है":
trait Handler[-A] {
def handle(a: A): Unit
}
एक कंट्रोवर्शियल टाइप पैरामीटर को "इनपुट" प्रकार माना जा सकता है। A
रूप में मार्किंग A
कॉन्ट्रावेरिएंट का दावा है कि Handler[X] <: Handler[Y]
ने X >: Y
। उदाहरण के लिए एक Handler[Animal]
एक वैध Handler[Cat]
, एक Handler[Animal]
रूप में भी बिल्लियों को संभालना चाहिए।
एक कंट्रावेरेंट प्रकार का पैरामीटर सहसंयोजक (आउटपुट) स्थिति में प्रकट नहीं हो सकता है। निम्नलिखित उदाहरण संकलित नहीं करेंगे क्योंकि हम दावा कर रहे हैं कि एक Contra[Animal] <: Contra[Cat]
, हालांकि एक Contra[Animal]
ने def produce: Animal
को def produce: Animal
जो Contra[Cat]
द्वारा आवश्यकतानुसार बिल्लियों का उत्पादन करने की गारंटी नहीं है!
trait Contra[-A] {
def handle(a: A): Unit
def produce: A
}
हालांकि सावधान रहें: ओवरलोडिंग रिज़ॉल्यूशन के प्रयोजनों के लिए, कॉन्ट्रैवेरियंटस भी काउंटरव्यूनेटिकली विरोधाभासी प्रकार के पैरामीटर पर एक प्रकार की विशिष्टता का विरोध करता है - Handler[Animal]
को Handler[Cat]
तुलना में "अधिक विशिष्ट" माना जाता है।
जैसा कि प्रकार के मापदंडों पर तरीकों को अधिभार देना संभव नहीं है, यह व्यवहार आम तौर पर केवल अंतर्निहित तर्कों को हल करते समय समस्याग्रस्त हो जाता है। निम्न उदाहरण में ofCat
, कभी नहीं इस्तेमाल किया जाएगा के रूप में की वापसी प्रकार ofAnimal
अधिक विशिष्ट है:
implicit def ofAnimal: Handler[Animal] = ???
implicit def ofCat: Handler[Cat] = ???
implicitly[Handler[Cat]].handle(new Cat)
इस व्यवहार को वर्तमान में dotty में बदलने के लिए स्लेट किया गया है, और इसीलिए (उदाहरण के रूप में) scala.math.Ordering
इसके प्रकार पैरामीटर T
पर अपरिवर्तनीय है। एक वर्कअराउंड आपके टाइपकालेज़ को अपरिवर्तनीय बनाना है, और उस घटना में निहित परिभाषा टाइप करना है जिसे आप इसे किसी दिए गए प्रकार के उपवर्गों पर लागू करना चाहते हैं:
trait Person
object Person {
implicit def ordering[A <: Person]: Ordering[A] = ???
}
एक संग्रह का सहसंयोजक
क्योंकि संग्रह आमतौर पर अपने तत्व प्रकार * में सहसंयोजक होते हैं, एक उपप्रकार का संग्रह पारित किया जा सकता है जहां एक सुपर प्रकार की उम्मीद की जाती है:
trait Animal { def name: String }
case class Dog(name: String) extends Animal
object Animal {
def printAnimalNames(animals: Seq[Animal]) = {
animals.foreach(animal => println(animal.name))
}
}
val myDogs: Seq[Dog] = Seq(Dog("Curly"), Dog("Larry"), Dog("Moe"))
Animal.printAnimalNames(myDogs)
// Curly
// Larry
// Moe
यह जादू की तरह प्रतीत नहीं हो सकता है, लेकिन यह तथ्य कि एक Seq[Dog]
एक ऐसी विधि द्वारा स्वीकार किया जाता है जो एक Seq[Animal]
अपेक्षा करता है वह एक उच्च-प्रकार के प्रकार (यहाँ: Seq
) की संपूर्ण अवधारणा है जो अपने प्रकार के पैरामीटर में सहसंयोजक है।
*
मानक पुस्तकालय के सेट होने का एक प्रतिरूप
एक अपरिवर्तनीय विशेषता पर सहसंयोजक
एक तरीका यह भी है कि एक ही पद्धति को सहसंयोजक तर्क को स्वीकार करने के बजाय पूरे लक्षण सहसंयोजक के पास होना चाहिए। यह आवश्यक हो सकता है क्योंकि आप T
का उपयोग एक कंट्रावेरेंट स्थिति में करना चाहते हैं, लेकिन फिर भी यह सहसंयोजक है।
trait LocalVariance[T]{
/// ??? throws a NotImplementedError
def produce: T = ???
// the implicit evidence provided by the compiler confirms that S is a
// subtype of T.
def handle[S](s: S)(implicit evidence: S <:< T) = {
// and we can use the evidence to convert s into t.
val t: T = evidence(s)
???
}
}
trait A {}
trait B extends A {}
object Test {
val lv = new LocalVariance[A] {}
// now we can pass a B instead of an A.
lv.handle(new B {})
}