Match multiple cases classes in scala

后端 未结 3 1342
离开以前
离开以前 2021-01-30 04:47

I\'m doing matching against some case classes and would like to handle two of the cases in the same way. Something like this:

abstract class Foo
case class A ext         


        
相关标签:
3条回答
  • 2021-01-30 05:24

    Well, it doesn't really make sense, does it? B and C are mutually exclusive, so either sb or sc get bound, but you don't know which, so you'd need further selection logic to decide which to use (given that they were bound to a Option[String], not a String). So there's nothing gained over this:

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

    Or this:

      l match {
        case A() => "A"
        case _: B => "B"
        case _: C => "C"
        case _ => "default"
      }
    
    0 讨论(0)
  • 2021-01-30 05:25

    There are a couple of ways that I can see to achieve what you are after, if you have some commonality between case classes. The first is to have the case classes extend a trait which declares the commonality, the second is to use a structural type which removes the need to extend your case classes.

     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))
       }
     }
    

    The structural type method generates a warning about erasure which, at present I'm not sure how to eliminate.

    0 讨论(0)
  • 2021-01-30 05:36

    Looks like you don't care about the values of the String parameters, and want to treat B and C the same, so:

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

    If you must, must, must extract the parameter and treat them in the same code block, you could:

    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"
      }
    }
    

    Though I feel it would be much cleaner to factor that out into a method:

    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"
      }
    }
    
    0 讨论(0)
提交回复
热议问题