简体   繁体   中英

Scala pattern matching down the class hierarchy

Is it possible to have Scala keep pattern matching down the class hierarchy after successfully matched a parent class? For example, I'm expecting the following code to print 1 and 2, but after matching S against T , Scala won't keep going and matching the next case, so the next case will never be reachable.

class T
class S extends T

new S match {
  case _: T => println(1)
  case _: S => println(2)
}

The first matching case is always selected. Just swap the order and test for the subtype S before testing for the parent class T. Or you can have a nested pattern match.

The closest i can think of would look like this ,

class T
class S extends T

new S match {
 case c@ (_: T  | _: S ) => println(1)
}

This way you could check if new S is of either of the types.

Scala pattern matching does not support fall-throughs. I actually asked this exact question a while ago ( Scala pattern matching - match multiple successful cases )

You would need to do it independently for every possible case.

If your actual use case is different (ie you have dozens of these conditions and you need to execute them sequentially in an elegant way) - I would possibly opt to use a different method and not pattern matching at all.

Possibly, what I would do (to maintain a functional paradigm) would be something like this:

class T
class S extends T

val myTestedVal = new S

((x:T) => ( 
    (x match { case z:S => (()=>println(2)) case _ => } ) ::
    (x match { case z:T => (()=>println(1)) case _ => } ) ::
    // Add other cases here
     Nil)) (myTestedVal).collect { case i:(()=>Unit) => i }.foreach(z => z())

The above sample code would print both 2 and 1 for S , and just 1 for T . What it does, is it basically runs the list of conditions, creating a list of functions to run based on the successful conditions, and then executes them in the foreach (which could also be modified to be a map if you need the functions to return meaningful values).

Note

The above method is definitely overkill for the OP's simple use-case. However, if you have multiple conditions that you want to execute in a "rule-engine" style, the above method is more elegant and "functional" than having a long chain of "if" statements.

Disclaimer: I am somewhat new to Scala and FP myself.

Think of pattern matching as a sequence of if-else if - else -if ... statements. You cannot execute more than one branch. The way around it is, depending on the complexity of your selectors, either nesting:

new S match {
   case t: T => println(1)
       t match {
         case _: S => println(2)
       }
}

or duplicating some of the actions in multiple branches:

new S match {
   case _: S => println(2); println(1)
   case _: T => println(1)
}

Or else using partial functions, which may be an overkill for your case, but just for completeness:

Option(new S).map { 
  case s:S => println(2); s
  case s => s
}.collect { 
  case _:T => println(1) 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM