खोज…


वाक्य - विन्यास

  • चयनकर्ता आंशिक मेल खाता है
  • चयनकर्ता मैच {केस विकल्प की सूची) // यह ऊपर का सबसे सामान्य रूप है

पैरामीटर

पैरामीटर विवरण
चयनकर्ता वह अभिव्यक्ति जिसका मान पैटर्न-मिलान किया जा रहा हो।
विकल्प case सूची -delimited विकल्प।

सरल पैटर्न मैच

यह उदाहरण दिखाता है कि इनपुट को कई मानों से कैसे मिलान किया जाए:

def f(x: Int): String = x match {
  case 1 => "One"
  case 2 => "Two"
  case _ => "Unknown!"
}

f(2)  // "Two"
f(3)  // "Unknown!"

लाइव डेमो

नोट: _ गिरावट या डिफ़ॉल्ट मामले के माध्यम से है , लेकिन इसकी आवश्यकता नहीं है।

def g(x: Int): String = x match {
  case 1 => "One"
  case 2 => "Two"
}

g(1)  // "One"
g(3)  // throws a MatchError

अपवाद को फेंकने से बचने के लिए, डिफ़ॉल्ट केस ( case _ => <do something> ) को संभालने के लिए यहां एक सबसे अच्छा कार्यात्मक-प्रोग्रामिंग अभ्यास है। ध्यान दें कि किसी केस के गुम होने पर केस क्लास में मेल करने से कंपाइलर को चेतावनी देने में मदद मिल सकती है। वही उपयोगकर्ता-परिभाषित प्रकारों के लिए जाता है जो एक सीलबंद विशेषता का विस्तार करते हैं। यदि मैच कुल होता है तो एक डिफ़ॉल्ट मामले की आवश्यकता नहीं हो सकती है

यह उन मानों के विरुद्ध मेल करना भी संभव है जो इनलाइन परिभाषित नहीं हैं। ये स्थिर पहचानकर्ता होने चाहिए, जो या तो पूंजीकृत नाम का उपयोग करके प्राप्त किए जाते हैं या बैकटिक्स संलग्न करते हैं।

One और two साथ कहीं और परिभाषित किया गया है, या फ़ंक्शन मापदंडों के रूप में पारित किया गया है:

val One: Int = 1
val two: Int = 2

उन्हें निम्न तरीके से मिलान किया जा सकता है:

def g(x: Int): String = x match {
  case One => "One"
  case `two` => "Two"
}

उदाहरण के लिए जावा के रूप में अन्य प्रोग्रामिंग भाषाओं के विपरीत, कोई गिरावट नहीं है। यदि कोई केस ब्लॉक किसी इनपुट से मेल खाता है, तो यह निष्पादित हो जाता है और मिलान समाप्त हो जाता है। इसलिए कम से कम विशिष्ट मामला अंतिम केस ब्लॉक होना चाहिए।

def f(x: Int): String = x match {
  case _ => "Default"
  case 1 => "One"
}

f(5) // "Default"
f(1) // "Default"

स्थिर पहचानकर्ता के साथ पैटर्न मिलान

मानक पैटर्न मिलान में, इस्तेमाल किया गया पहचानकर्ता किसी भी पहचानकर्ता को संलग्न दायरे में छाया देगा। कभी-कभी एनक्लोजिंग स्कोप के वैरिएबल पर मिलान करना आवश्यक होता है।

निम्न उदाहरण फ़ंक्शन एक चरित्र और ट्यूपल्स की सूची लेता है और ट्यूपल्स की एक नई सूची देता है। यदि एक टुपल्स में वर्ण पहले तत्व के रूप में मौजूद है, तो दूसरा तत्व बढ़ा हुआ है। यदि यह अभी तक सूची में मौजूद नहीं है, तो एक नया टपल बनाया जाता है।

def tabulate(char: Char, tab: List[(Char, Int)]): List[(Char, Int)] = tab match {
  case Nil => List((char, 1))
  case (`char`, count) :: tail => (char, count + 1) :: tail
  case head :: tail => head :: tabulate(char, tail)
}

ऊपर दर्शाया गया है कि पैटर्न मिलान जहां विधि के इनपुट, char , को पैटर्न मैच में 'स्थिर' रखा जाता है: अर्थात, यदि आप tabulate('x', ...) , तो पहले केस स्टेटमेंट की व्याख्या इस प्रकार की जाएगी:

case('x', count) => ...

स्काला टिक मार्क के साथ सीमांकित किसी भी वैरिएबल की पहचान एक स्थिर पहचानकर्ता के रूप में करेगा: यह किसी भी वैरिएबल की व्याख्या करेगा जो उसी तरह से कैपिटल लेटर से शुरू होता है।

एक Seq पर पैटर्न मिलान

संग्रह में तत्वों की सटीक संख्या की जांच करने के लिए

def f(ints: Seq[Int]): String = ints match {
  case Seq() =>
      "The Seq is empty !"
  case Seq(first) =>
      s"The seq has exactly one element : $first"
  case Seq(first, second) =>
      s"The seq has exactly two elements : $first, $second"
  case  s @ Seq(_, _, _) => 
      s"s is a Seq of length three and looks like ${s}"  // Note individual elements are not bound to their own names.
  case s: Seq[Int] if s.length == 4 =>
      s"s is a Seq of Ints of exactly length 4"  // Again, individual elements are not bound to their own names.
  case _ =>
      "No match was found!"
}

लाइव डेमो

पहला (स) तत्व निकालने के लिए और शेष को संग्रह के रूप में रखने के लिए:

def f(ints: Seq[Int]): String = ints match {
  case Seq(first, second, tail @ _*) =>
      s"The seq has at least two elements : $first, $second. The rest of the Seq is $tail"
  case Seq(first, tail @ _*) =>
      s"The seq has at least one element : $first. The rest of the Seq is $tail"
  // alternative syntax
  // here of course this one will never match since it checks
  // for the same thing as the one above
  case first +: tail =>
      s"The seq has at least one element : $first. The rest of the Seq is $tail"
  case _ =>
      "The seq didn't match any of the above, so it must be empty"
}

सामान्य तौर पर, अनुक्रम के निर्माण के लिए उपयोग किए जा सकने वाले किसी भी रूप का उपयोग मौजूदा अनुक्रम के विरुद्ध मिलान करने के लिए किया जा सकता है।

ध्यान दें कि Nil और :: का उपयोग करते समय काम करेगा जब पैटर्न एक अनुक्रम से मेल खाता है, यह इसे List परिवर्तित करता है, और अप्रत्याशित परिणाम हो सकता है। इससे बचने के लिए खुद को Seq( ...) और +: पर विवश करें।

ध्यान दें कि :: का उपयोग करते समय WrappedArray , Vector आदि के लिए काम नहीं करेगा, देखें:

scala> def f(ints:Seq[Int]) = ints match {
     | case h :: t => h
     | case _ => "No match"
     | }
f: (ints: Seq[Int])Any

scala> f(Array(1,2))
res0: Any = No match

और +: साथ +:

scala> def g(ints:Seq[Int]) = ints match {
     | case h+:t => h
     | case _ => "No match"
     | }
g: (ints: Seq[Int])Any

scala> g(Array(1,2).toSeq)
res4: Any = 1

गार्ड (यदि अभिव्यक्ति)

अगर पैटर्न मिलान के दौरान अतिरिक्त तर्क प्रदान करने के लिए अभिव्यक्ति के साथ केस स्टेटमेंट को जोड़ा जा सकता है।

def checkSign(x: Int): String = {
    x match {
      case a if a < 0 => s"$a is a negative number"
      case b if b > 0 => s"$b is a positive number"
      case c => s"$c neither positive nor negative"
    }
}

यह सुनिश्चित करना महत्वपूर्ण है कि आपके गार्ड गैर-थकाऊ मैच न बनाएं (कंपाइलर अक्सर इसे पकड़ नहीं पाएगा):

def f(x: Option[Int]) = x match {
    case Some(i) if i % 2 == 0 => doSomething(i)
    case None    => doSomethingIfNone
}

यह विषम संख्याओं पर एक MatchError फेंकता है। आपको या तो सभी मामलों के लिए खाता होना चाहिए, या वाइल्डकार्ड मैच केस का उपयोग करना चाहिए:

def f(x: Option[Int]) = x match {
    case Some(i) if i % 2 == 0 => doSomething(i)
    case _ => doSomethingIfNoneOrOdd
}

केस कक्षाओं के साथ पैटर्न मिलान

हर केस क्लास एक एक्सट्रैक्टर को परिभाषित करता है जिसका उपयोग पैटर्न मिलान के समय केस क्लास के सदस्यों को पकड़ने के लिए किया जा सकता है:

case class Student(name: String, email: String)

def matchStudent1(student: Student): String = student match {
    case Student(name, email) => s"$name has the following email: $email" // extract name and email
}

पैटर्न-मैचिंग के सभी सामान्य नियम लागू होते हैं - आप मिलान को नियंत्रित करने के लिए गार्ड और स्थिर भाव का उपयोग कर सकते हैं:

def matchStudent2(student: Student): String = student match {
    case Student("Paul", _) => "Matched Paul" // Only match students named Paul, ignore email
    case Student(name, _) if name == "Paul" => "Matched Paul" // Use a guard to match students named Paul, ignore email
    case s if s.name == "Paul" => "Matched Paul" // Don't use extractor; use a guard to match students named Paul, ignore email
    case Student("Joe", email) => s"Joe has email $email" // Match students named Joe, capture their email
    case Student(name, email) if name == "Joe" => s"Joe has email $email" // use a guard to match students named Joe, capture their email
    case Student(name, email) => s"$name has email $email." // Match all students, capture name and email 
}

एक विकल्प पर मिलान

यदि आप एक विकल्प प्रकार पर मिलान कर रहे हैं:

def f(x: Option[Int]) = x match {
    case Some(i) => doSomething(i)
    case None    => doSomethingIfNone
}

यह कार्यात्मक रूप से fold , या map / getOrElse का उपयोग करने के बराबर है:

def g(x: Option[Int]) = x.fold(doSomethingIfNone)(doSomething)
def h(x: Option[Int]) = x.map(doSomething).getOrElse(doSomethingIfNone)

पैटर्न मिलान सील लक्षण

जब पैटर्न एक ऐसी वस्तु से मेल खाता है जिसका प्रकार एक मुहरबंद विशेषता है, तो स्काला संकलन-समय पर जांच करेगा कि सभी मामले 'थकाऊ' हैं:

sealed trait Shape
case class Square(height: Int, width: Int) extends Shape
case class Circle(radius: Int) extends Shape
case object Point extends Shape


def matchShape(shape: Shape): String = shape match {
    case Square(height, width) => "It's a square"
    case Circle(radius)        => "It's a circle"
    //no case for Point because it would cause a compiler warning.
}

यदि Shape लिए एक नया case class बाद में जोड़ा जाता है, तो Shape पर सभी match स्टेटमेंट एक कंपाइलर चेतावनी फेंकना शुरू कर देंगे। यह पूरी तरह से रिफैक्टिंग को आसान बनाता है: कंपाइलर डेवलपर को उन सभी कोड के लिए सचेत करेगा जिन्हें अपडेट करने की आवश्यकता है।

रेगेक्स के साथ पैटर्न मिलान

val emailRegex: Regex = "(.+)@(.+)\\.(.+)".r

"[email protected]" match {
  case emailRegex(userName, domain, topDomain) => println(s"Hi $userName from $domain")
  case _ => println(s"This is not a valid email.")
}

इस उदाहरण में, रेगेक्स प्रदान किए गए ईमेल पते से मेल खाने का प्रयास करता है। यदि ऐसा होता है, तो userName और domain निकाला जाता है और मुद्रित किया जाता है। topDomain भी निकाला जाता है, लेकिन इस उदाहरण में इसके साथ कुछ भी नहीं किया जाता है। कॉलिंग .r एक स्ट्रिंग पर str के बराबर है new Regex(str)r फ़ंक्शन एक अंतर्निहित रूपांतरण के माध्यम से उपलब्ध है।

पैटर्न बांधने की मशीन (@)

@ चिह्न एक पैटर्न मैच के दौरान एक चर को एक नाम से बांधता है। बाध्य चर या तो पूरी तरह से मिलान की गई वस्तु या मिलान वाली वस्तु का हिस्सा हो सकता है:

sealed trait Shape
case class Rectangle(height: Int, width: Int) extends Shape
case class Circle(radius: Int) extends Shape
case object Point extends Shape

(Circle(5): Shape) match {
  case Rectangle(h, w) => s"rectangle, $h x $w."
  case Circle(r) if r > 9 => s"large circle"
  case c @ Circle(_) => s"small circle: ${c.radius}"  // Whole matched object is bound to c
  case Point => "point"
}

> res0: String = small circle: 5

बाध्य पहचानकर्ता का उपयोग सशर्त फिल्टर में किया जा सकता है। इस प्रकार:

case Circle(r) if r > 9 => s"large circle"

के रूप में लिखा जा सकता है:

case c @ Circle(_) if c.radius > 9 => s"large circle"

नाम केवल मिलान किए गए पैटर्न के एक हिस्से के लिए बाध्य हो सकता है:

Seq(Some(1), Some(2), None) match {
  // Only the first element of the matched sequence is bound to the name 'c'
  case Seq(c @ Some(1), _*) => head
  case _ => None
}

> res0: Option[Int] = Some(1)

पैटर्न मिलान प्रकार

पैटर्न मिलान का उपयोग isInstanceOf[B] बजाय, उदाहरण के प्रकार को जांचने के लिए भी किया जा सकता है:

val anyRef: AnyRef = ""
                                                  
anyRef match {
  case _: Number       => "It is a number"
  case _: String       => "It is a string"
  case _: CharSequence => "It is a char sequence"
}
//> res0: String = It is a string

मामलों का क्रम महत्वपूर्ण है:

anyRef match {
  case _: Number       => "It is a number"
  case _: CharSequence => "It is a char sequence"
  case _: String       => "It is a string"
}
//> res1: String = It is a char sequence

इस तरीके से यह गिरावट के माध्यम से कार्यक्षमता के बिना एक शास्त्रीय 'स्विच' बयान के समान है। हालाँकि, आप प्रश्न में टाइप से मान और 'अर्क' मानों को भी जोड़ सकते हैं। उदाहरण के लिए:

case class Foo(s: String)
case class Bar(s: String)
case class Woo(s: String, i: Int)

def matcher(g: Any):String = {
  g match {
    case Bar(s) => s + " is classy!" 
    case Foo(_) => "Someone is wicked smart!"
    case Woo(s, _) => s + " is adventerous!"
    case _ => "What are we talking about?"
  }
}

print(matcher(Foo("Diana")))  // prints 'Diana is classy!'
print(matcher(Bar("Hadas")))  // prints 'Someone is wicked smart!'
print(matcher(Woo("Beth", 27)))   // prints 'Beth is adventerous!'
print(matcher(Option("Katie")))  // prints 'What are we talking about?'

ध्यान दें कि Foo और Woo मामले में हम अंडरस्कोर ( _ ) का उपयोग 'अनबाउंड वैरिएबल से मिलान करने के लिए' करते हैं। यह कहना है कि मूल्य (इस मामले में Hadas और 27 क्रमशः) एक नाम के लिए बाध्य नहीं है और इस तरह उस मामले के लिए हैंडलर में उपलब्ध नहीं है। यह उस मूल्य के बारे में चिंता किए बिना किसी भी 'मूल्य' का मिलान करने के लिए उपयोगी शॉर्टहैंड है।

पैटर्न मिलान तालिकाओं या लुकअप के रूप में संकलित किया गया

@switch एनोटेशन कंपाइलर को बताता है कि match स्टेटमेंट को बाइटकोड स्तर पर सिंगल tableswitch इंस्ट्रक्शन के साथ बदला जा सकता है। यह एक मामूली अनुकूलन है जो रनटाइम के दौरान अनावश्यक तुलना और चर भार को हटा सकता है।

@switch एनोटेशन केवल शाब्दिक स्थिरांक और final val पहचानकर्ताओं के खिलाफ मैचों के लिए काम करता है। यदि पैटर्न मैच tableswitch / lookupswitch रूप में संकलित नहीं किया जा सकता है, तो कंपाइलर एक चेतावनी देगा।

import annotation.switch

def suffix(i: Int) = (i: @switch) match {
  case 1 => "st"
  case 2 => "nd"
  case 3 => "rd"
  case _ => "th"
}

परिणाम एक सामान्य पैटर्न मैच के समान हैं:

scala> suffix(2)
res1: String = "2nd"

scala> suffix(4)
res2: String = "4th"

स्काला डॉक्यूमेंटेशन (2.8+) से - @switch :

एक मिलान अभिव्यक्ति पर लागू होने वाला एनोटेशन। यदि मौजूद है, तो संकलक यह सत्यापित करेगा कि मैच टेबलवॉच या लुकअप में संकलित किया गया है, और अगर यह सशर्त अभिव्यक्तियों की एक श्रृंखला में संकलित करता है, तो एक त्रुटि जारी करता है।

जावा विशिष्टता से:

एक बार में कई पैटर्न का मिलान

| एक ही परिणाम प्राप्त करने के लिए कई आदानों के खिलाफ एक एकल मामले बयान मैच के लिए इस्तेमाल किया जा सकता है:

def f(str: String): String = str match {
  case "foo" | "bar" => "Matched!"
  case _ => "No match."
}

f("foo")  // res0: String = Matched!
f("bar")  // res1: String = Matched!
f("fubar")  // res2: String = No match.

ध्यान दें कि मिलान मूल्यों इस तरह से अच्छी तरह से काम करते हुए, प्रकार के निम्नलिखित मिलान समस्याएं पैदा कर देगा:

sealed class FooBar
case class Foo(s: String) extends FooBar
case class Bar(s: String) extends FooBar

val d = Foo("Diana")
val h = Bar("Hadas")

// This matcher WILL NOT work.
def matcher(g: FooBar):String = {
  g match {
    case Foo(s) | Bar(s) => print(s)  // Won't work: s cannot be resolved
    case Foo(_) | Bar(_) => _         // Won't work: _ is an unbound placeholder
    case _ => "Could not match"
  }
}

यदि बाद वाले मामले में ( _ साथ) आपको अनबाउंड वैरिएबल के मूल्य की आवश्यकता नहीं है और बस कुछ और करना चाहते हैं, तो आप ठीक हैं:

def matcher(g: FooBar):String = {
  g match {
    case Foo(_) | Bar(_) => "Is either Foo or Bar."  // Works fine
    case _ => "Could not match"
  }
}

अन्यथा, आपको अपने मामलों को विभाजित करने के लिए छोड़ दिया जाता है:

def matcher(g: FooBar):String = {
  g match {
    case Foo(s) => s 
    case Bar(s) => s
    case _ => "Could not match"
  }
}

ट्यूपल्स पर पैटर्न का मिलान

यह देखते हुए निम्न List tuples के:

val pastries = List(("Chocolate Cupcake", 2.50), 
                    ("Vanilla Cupcake", 2.25),
                    ("Plain Muffin", 3.25))

पैटर्न मिलान का उपयोग प्रत्येक तत्व को अलग तरीके से संभालने के लिए किया जा सकता है:

pastries foreach { pastry =>
  pastry match {
    case ("Plain Muffin", price) => println(s"Buying muffin for $price")
    case p if p._1 contains "Cupcake" => println(s"Buying cupcake for ${p._2}")
    case _ => println("We don't sell that pastry")
  }
}

पहला मामला दिखाता है कि एक विशिष्ट स्ट्रिंग के खिलाफ कैसे मेल खाता है और इसी कीमत प्राप्त करता है। दूसरा मामला टुपल के तत्वों के खिलाफ मिलान करने के लिए अगर और टपल निष्कर्षण का उपयोग दिखाता है।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow