स्कैला में कई मामलों की कक्षाओं का मिलान करें


100

मैं कुछ केस क्लासेस के खिलाफ मैच कर रहा हूं और दो मामलों को उसी तरह से हैंडल करना चाहूंगा। कुछ इस तरह:

abstract class Foo
case class A extends Foo
case class B(s:String) extends Foo
case class C(s:String) extends Foo


def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case B(sb) | C(sc) => "B"
    case _ => "default"
  }
}

लेकिन जब मैं ऐसा करता हूं तो मुझे त्रुटि मिलती है:

(fragment of test.scala):10: error: illegal variable in pattern alternative
    case B(sb) | C(sc) => "B"

मैं इसे काम कर सकता हूं मैं बी और सी की परिभाषा से मापदंडों को हटा सकता हूं लेकिन मैं पैरामेट्स के साथ कैसे मेल कर सकता हूं?

जवाबों:


145

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

def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case B(_) | C(_) => "B"
    case _ => "default"
  }
}

यदि आपको आवश्यक रूप से पैरामीटर निकालना होगा और उन्हें एक ही कोड ब्लॉक में व्यवहार करना होगा, तो आप कर सकते हैं:

def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case bOrC @ (B(_) | C(_)) => {
      val s = bOrC.asInstanceOf[{def s: String}].s // ugly, ugly
      "B(" + s + ")"
    }
    case _ => "default"
  }
}

हालांकि मुझे लगता है कि यह एक विधि में फैले कारक के लिए बहुत साफ होगा:

def doB(s: String) = { "B(" + s + ")" }

def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case B(s) => doB(s)
    case C(s) => doB(s)
    case _ => "default"
  }
}

हालांकि मेरा उदाहरण यह नहीं दिखाता है कि मुझे उन परमों की आवश्यकता है। लगता है कि मुझे बस एक वस्तु का उपयोग करना होगा। धन्यवाद!
समयदिनेसी

4
क्या कोई कारण है कि स्केला "केस A (aString) | केस B (aString) => println (aString)" की अनुमति नहीं देता है? तब तक लगता है जब तक ए और बी दोनों के लिए स्ट्रींग का प्रकार समान है, इसे अनुमति दी जानी चाहिए। आपका अंतिम उदाहरण ऐसा लगता है कि बी और सी मामलों की नकल नहीं करना बेहतर होगा।
जेम्स मूर

37
मैं तुम्हें एक और आगे जाऊँगा। मुझे लगता है कि यह case A(x) | B(x) => println(x)अनुमति देना अच्छा होगा जहां xए (एक्स) और बी (एक्स) के प्रकार के सिस्टम में ऊपरी बाउंड के लिए सेट किया गया है।
मिच बोलिविंस

1
@ मिच लिफ्ट: आप मुद्दों के लिए वोट कर सकते हैं ।scala-lang.org/browse/ SUGGEST-25 (वैकल्पिक पैटर्न में चर बंधन की अनुमति दें)
एरिक कपलुन

2
उन लोगों के लिए जो सोच रहे हैं कि @ प्रतीक वहां क्या कर रहा है: scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html
साइलेंटडाइरे

9

ऐसे कुछ तरीके हैं जो मैं देख सकता हूं कि आप क्या कर रहे हैं, अगर आपके पास मामला वर्गों के बीच कुछ समानता है। पहली बात यह है कि केस क्लासेस एक विशेषता का विस्तार करता है जो सामान्यता की घोषणा करता है, दूसरा एक संरचनात्मक प्रकार का उपयोग करना है जो आपके केस क्लासेस का विस्तार करने की आवश्यकता को दूर करता है।

 object MuliCase {
   abstract class Foo
   case object A extends Foo

   trait SupportsS {val s: String}

   type Stype = Foo {val s: String}

   case class B(s:String) extends Foo
   case class C(s:String) extends Foo

   case class D(s:String) extends Foo with SupportsS
   case class E(s:String) extends Foo with SupportsS

   def matcher1(l: Foo): String = {
     l match {
       case A        => "A"
       case s: Stype => println(s.s); "B"
       case _        => "default"
     }
   }

   def matcher2(l: Foo): String = {
     l match {
       case A            => "A"
       case s: SupportsS => println(s.s); "B"
       case _            => "default"
     }
   }

   def main(args: Array[String]) {
     val a = A
     val b = B("B's s value")
     val c = C("C's s value")

     println(matcher1(a))
     println(matcher1(b))
     println(matcher1(c))

     val d = D("D's s value")
     val e = E("E's s value")

     println(matcher2(d))
     println(matcher2(e))
   }
 }

संरचनात्मक प्रकार की विधि इरेज़र के बारे में एक चेतावनी उत्पन्न करती है, जो वर्तमान में मुझे यकीन नहीं है कि कैसे खत्म किया जाए।


6

खैर, यह वास्तव में कोई मतलब नहीं है, यह करता है? बी और सी पारस्परिक रूप से अनन्य हैं, इसलिए या तो एसबी या एससी बाध्य हो जाते हैं, लेकिन आपको पता नहीं है कि, इसलिए आपको यह तय करने के लिए आगे चयन तर्क की आवश्यकता होगी कि कौन सा उपयोग करना है (यह देखते हुए कि वे एक विकल्प [स्ट्रिंग] से बंधे थे, नहीं) एक स्ट्रिंग)। इसलिए इस पर कुछ भी प्राप्त नहीं हुआ है:

  l match {
    case A() => "A"
    case B(sb) => "B(" + sb + ")"
    case C(sc) => "C(" + sc + ")"
    case _ => "default"
  }

या यह:

  l match {
    case A() => "A"
    case _: B => "B"
    case _: C => "C"
    case _ => "default"
  }

क्या होगा अगर आपको परवाह नहीं है कि क्या बी या सी का मिलान किया गया था? निम्नलिखित कोड में कहें: args match { case Array("-x", hostArg) => (hostArg, true); case Array(hostArg, "-x") => (hostArg, true) }हालांकि, मैं देखता हूं कि यह सामान्य मामला नहीं है और यह कि स्थानीय विधि बनाना एक विकल्प है। हालाँकि, यदि विकल्प सुविधाजनक है, तो केस विकल्प होने की बहुत कम संभावना है। वास्तव में, कुछ एमएल बोलियों में आपके पास एक जैसी विशेषता होती है और आप अभी भी चर को बाँध सकते हैं, जब तक कि प्रत्येक विकल्प पर एक ही प्रकार के साथ बाध्य (IIRC) हो।
ब्‍लॉसरब्‍लेड

तुम सही हो। यदि आप केवल प्रकारों के बारे में परवाह करते हैं और न कि मूल्यों के बारे में और न ही कौन सा प्रकार प्रस्तुत किया गया है, तो विवादास्पद प्रकार-आधारित मिलान सार्थक और उपलब्ध है।
रान्डेल शुल्ज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.