Матч "провал": выполнение одного и того же фрагмента кода для нескольких случаев?

Что такое Scala способ записи следующего кода:

 int i;

 switch(i) {
   case 1:  
         a();
         break;

   case 2:
   case 15:
        b();
        c();
        break;

   default: foo()        
 } 

т.е. что такое идиоматический способ выполнения одного и того же фрагмента кода на основе нескольких значений кода?

 i match {
   case 1  => a    
   case 2  =>
   case 15 => { b
                c }
   case _ => foo        
 } 

Не похоже на трюк, так как Scala оценивает значение соответствия на основе первого совпадающего случая, то есть если я = 2, код ничего не вернет.

Спасибо за помощь!

Ответ 1

В соответствии с этот разговор нет провала, но вы можете использовать |.

Это должно сделать трюк:

i match {
  case 1  => a    
  case 2 | 15 => b
                 c
  case _ => foo        
} 

Ответ 2

Операторы case могут фактически включать дополнительные логические защитники, используя стандартную инструкцию if. Таким образом, вы можете сделать что-то вроде:

i match {
  case x if x == 1 => a
  case x if (x == 2 | x == 15) => b; c;
  case _ => foo
}

Соответствующие охранники могут быть любой логической функцией или композицией функций, поэтому она дает ей намного больше мощности, чем стандартный оператор switch в Java.

Ответ 3

Хотя здесь не применимо, для более сложных проблем вы можете "провалиться" в некотором смысле, используя функцию andThen для частичных функций.

 def do_function_a() { println("a"); }
 def do_function_b() { println("b"); }
 val run_function:PartialFunction[String, String] = { 
       case "a" => do_function_a(); "b"
       case "b" => do_function_b(); "c"
 }

 (run_function andThen run_function)("a") // a\nb

Ответ 4

Если вы имеете дело с фактическими классами (вместо строк или ints), вам нужно _: перед каждым классом, чтобы сделать их образцом, прежде чем присоединять их к |.

sealed trait ShipCondition
case class ShipOnFire() extends ShipCondition
case class FoodSucks() extends ShipCondition
case class MateySnoresTooLoud() extends ShipCondition
case class Ok() extends ShipCondition

val condition = ShipOnFire()

def checkCondition(cond: ShipCondition): Unit = {
  cond match {
    case c @ (_: ShipOnFire | _: FoodSucks) => println("Abandon Ship!") // can also use `c` for something. It has the type ShipCondition
    case (_: MateySnoresTooLoud | _: Ok) => println("Deal with it!")
  }
}

checkCondition(condition) // Abandon Ship!

У вас тоже неплохая проверка! Обратите внимание, что вы не можете выполнить деструктуризацию класса case при использовании альтернативного сопоставления шаблонов (например, case (MateySnoresTooLoud(str) | _: Ok) => не сможет скомпилироваться.