Scala Language
केस क्लासेस
खोज…
वाक्य - विन्यास
- मामला वर्ग Foo () // बिना किसी पैरामीटर वाले केस वर्गों की एक खाली सूची होनी चाहिए
- केस क्लास फू (ए 1: ए 1, ..., ए एन: एएन) // फ़ील्ड ए 1 ... ए एन के साथ केस क्लास बनाएं
- केस ऑब्जेक्ट बार // एक सिंगलटन केस क्लास बनाएं
केस क्लास इक्वलिटी
केस क्लासेस द्वारा मुफ्त में प्रदान की जाने वाली एक विशेषता एक ऑटो-जनरेटेड equals
तरीका है, जो वस्तुओं के संदर्भ समानता की जांच करने के बजाय सभी व्यक्तिगत सदस्य क्षेत्रों के मूल्य समानता की जांच करता है।
साधारण वर्गों के साथ:
class Foo(val i: Int)
val a = new Foo(3)
val b = new Foo(3)
println(a == b)// "false" because they are different objects
केस कक्षाओं के साथ:
case class Foo(i: Int)
val a = Foo(3)
val b = Foo(3)
println(a == b)// "true" because their members have the same value
जनरेट कोड कलाकृतियाँ
case
संशोधक स्काला संकलक को वर्ग के लिए सामान्य बॉयलरप्लेट कोड उत्पन्न करने का कारण बनता है। इस कोड को मैन्युअल रूप से लागू करना थकाऊ और त्रुटियों का स्रोत है। निम्नलिखित केस क्लास परिभाषा:
case class Person(name: String, age: Int)
... निम्नलिखित कोड स्वतः उत्पन्न होगा:
class Person(val name: String, val age: Int)
extends Product with Serializable
{
def copy(name: String = this.name, age: Int = this.age): Person =
new Person(name, age)
def productArity: Int = 2
def productElement(i: Int): Any = i match {
case 0 => name
case 1 => age
case _ => throw new IndexOutOfBoundsException(i.toString)
}
def productIterator: Iterator[Any] =
scala.runtime.ScalaRunTime.typedProductIterator(this)
def productPrefix: String = "Person"
def canEqual(obj: Any): Boolean = obj.isInstanceOf[Person]
override def hashCode(): Int = scala.runtime.ScalaRunTime._hashCode(this)
override def equals(obj: Any): Boolean = this.eq(obj) || obj match {
case that: Person => this.name == that.name && this.age == that.age
case _ => false
}
override def toString: String =
scala.runtime.ScalaRunTime._toString(this)
}
case
संशोधक भी एक साथी वस्तु उत्पन्न करता है:
object Person extends AbstractFunction2[String, Int, Person] with Serializable {
def apply(name: String, age: Int): Person = new Person(name, age)
def unapply(p: Person): Option[(String, Int)] =
if(p == null) None else Some((p.name, p.age))
}
जब किसी object
लागू किया जाता object
, तो case
संशोधक समान (यद्यपि कम नाटकीय) प्रभाव होता है। यहाँ प्राथमिक लाभ एक हैं toString
कार्यान्वयन और एक hashCode
मूल्य कि प्रक्रियाओं पर एक जैसी है। ध्यान दें कि केस ऑब्जेक्ट्स (सही ढंग से) संदर्भ समानता का उपयोग करते हैं:
object Foo extends Product with Serializable {
def productArity: Int = 0
def productIterator: Iterator[Any] =
scala.runtime.ScalaRunTime.typedProductIterator(this)
def productElement(i: Int): Any =
throw new IndexOutOfBoundsException(i.toString)
def productPrefix: String = "Foo"
def canEqual(obj: Any): Boolean = obj.isInstanceOf[this.type]
override def hashCode(): Int = 70822 // "Foo".hashCode()
override def toString: String = "Foo"
}
मैन्युअल रूप से उन तरीकों को लागू करना अभी भी संभव है जो अन्यथा वर्ग और स्वयं के साथी ऑब्जेक्ट में case
संशोधक द्वारा प्रदान किए जाएंगे।
केस क्लास बेसिक्स
नियमित कक्षाओं की तुलना में - केस क्लास संकेतन कई लाभ प्रदान करता है:
सभी कंस्ट्रक्टर तर्क
public
और प्रारंभिक ऑब्जेक्ट्स पर एक्सेस किए जा सकते हैं (आमतौर पर यह मामला नहीं है, जैसा कि यहां दिखाया गया है):case class Dog1(age: Int) val x = Dog1(18) println(x.age) // 18 (success!) class Dog2(age: Int) val x = new Dog2(18) println(x.age) // Error: "value age is not a member of Dog2"
यह निम्नलिखित विधियों के लिए एक कार्यान्वयन प्रदान करता है:
toString
,equals
,hashCode
(गुणों के आधार पर),copy
,apply
औरunapply
:case class Dog(age: Int) val d1 = Dog(10) val d2 = d1.copy(age = 15)
यह पैटर्न मिलान के लिए एक सुविधाजनक तंत्र प्रदान करता है:
sealed trait Animal // `sealed` modifier allows inheritance within current build-unit only case class Dog(age: Int) extends Animal case class Cat(owner: String) extends Animal val x: Animal = Dog(18) x match { case Dog(x) => println(s"It's a $x years old dog.") case Cat(x) => println(s"This cat belongs to $x.") }
केस क्लासेस और इम्यूटेबिलिटी
स्केल संकलक पैरामीटर सूची में प्रत्येक तर्क को val
साथ डिफ़ॉल्ट रूप से उपसर्ग करता है। इसका मतलब है कि, डिफ़ॉल्ट रूप से, केस कक्षाएं अपरिवर्तनीय हैं। प्रत्येक पैरामीटर को एक एक्सेसर विधि दी जाती है, लेकिन कोई उत्परिवर्ती विधियां नहीं होती हैं। उदाहरण के लिए:
case class Foo(i: Int)
val fooInstance = Foo(1)
val j = fooInstance.i // get
fooInstance.i = 2 // compile-time exception (mutation: reassignment to val)
किसी मामले की श्रेणी में एक पैरामीटर की घोषणा करना क्योंकि var
डिफ़ॉल्ट व्यवहार को ओवरराइड करता है और केस क्लास को परिवर्तनशील बनाता है:
case class Bar(var i: Int)
val barInstance = Bar(1)
val j = barInstance.i // get
barInstance.i = 2 // set
एक अन्य उदाहरण जब एक केस क्लास 'म्यूटेबल' होता है, जब केस क्लास में वैल्यू म्यूटेबल होती है:
import scala.collection._
case class Bar(m: mutable.Map[Int, Int])
val barInstance = Bar(mutable.Map(1 -> 2))
barInstance.m.update(1, 3) // mutate m
barInstance // Bar(Map(1 -> 3)
ध्यान दें कि यहाँ होने वाला in उत्परिवर्तन ’उस मानचित्र में होता है जो m
इंगित करता है, केवल m
को नहीं। इस प्रकार, यदि किसी सदस्य के रूप में किसी अन्य वस्तु में m
होता है, तो यह परिवर्तन को भी देखेगा। ध्यान दें कि निम्नलिखित उदाहरण बदलते instanceA
भी कैसे बदलता है instanceB
:
import scala.collection.mutable
case class Bar(m: mutable.Map[Int, Int])
val m = mutable.Map(1 ->2)
val barInstanceA = Bar(m)
val barInstanceB = Bar(m)
barInstanceA.m.update(1,3)
barInstanceA // Bar = Bar(Map(1 -> 3))
barInstanceB // Bar = Bar(Map(1 -> 3))
m // scala.collection.mutable.Map[Int,Int] = Map(1 -> 3)
कुछ परिवर्तन के साथ एक वस्तु की प्रतिलिपि बनाएँ
केस क्लासेस एक copy
मेथड प्रदान करता है जो एक नया ऑब्जेक्ट बनाता है जो कुछ बदलावों के साथ पुराने फ़ील्ड के समान शेयर करता है।
हम इस सुविधा का उपयोग पिछले ऑब्जेक्ट से एक नई वस्तु बनाने के लिए कर सकते हैं जिसमें कुछ समान विशेषताएं हैं। इस सुविधा को प्रदर्शित करने के लिए यह सरल केस क्लास:
case class Person(firstName: String, lastName: String, grade: String, subject: String)
val putu = Person("Putu", "Kevin", "A1", "Math")
val mark = putu.copy(firstName = "Ketut", lastName = "Mark")
// mark: People = People(Ketut,Mark,A1,Math)
इस उदाहरण में हम देख सकते हैं कि दो वस्तुएं समान विशेषताओं ( grade = A1
, subject = Math
) को साझा करती हैं, सिवाय इसके कि उन्हें कॉपी ( firstName
और lastName
) में निर्दिष्ट किया गया है।
टाइप सेफ्टी के लिए सिंगल एलिमेंट केस क्लासेस
प्रकार सुरक्षा प्राप्त करने के लिए कभी-कभी हम अपने डोमेन पर आदिम प्रकारों के उपयोग से बचना चाहते हैं। उदाहरण के लिए, किसी Person
के name
साथ कल्पना name
। आमतौर पर, हम String
रूप में name
को एनकोड करेंगे। हालांकि, यह एक मिश्रण करने के लिए कठिन नहीं होगा String
एक का प्रतिनिधित्व Person
के name
एक साथ String
एक त्रुटि संदेश का प्रतिनिधित्व:
def logError(message: ErrorMessage): Unit = ???
case class Person(name: String)
val maybeName: Either[String, String] = ??? // Left is error, Right is name
maybeName.foreach(logError) // But that won't stop me from logging the name as an error!
इस तरह के नुकसान से बचने के लिए आप डेटा को इस तरह से एनकोड कर सकते हैं:
case class PersonName(value: String)
case class ErrorMessage(value: String)
case class Person(name: PersonName)
और अब हमारा कोड संकलित नहीं करेगा यदि हम PersonName
को ErrorMessage
, या यहां तक कि एक साधारण String
साथ PersonName
।
val maybeName: Either[ErrorMessage, PersonName] = ???
maybeName.foreach(reportError) // ERROR: tried to pass PersonName; ErrorMessage expected
maybeName.swap.foreach(reportError) // OK
लेकिन यह एक छोटे से रन ओवरहेड को PersonName
क्योंकि अब हमें अपने PersonName
कंटेनर से बॉक्स / अनबॉक्स String
एस / PersonName
। आदेश में इस से बचने के लिए, एक बना सकते हैं PersonName
और ErrorMessage
मूल्य वर्गों:
case class PersonName(val value: String) extends AnyVal
case class ErrorMessage(val value: String) extends AnyVal