Coincidencia de patrones de múltiples tipos de Scala


80

Me pregunto cómo puedo utilizar la coincidencia de patrones de varios tipos. Yo tengo:

abstract class MyAbstract

case class MyFirst extends MyAbstract
case class MySecond extends MyAbstract
case class MyThird extends MyAbstract // shouldn't be matched and shouldn't call doSomething()

val x: MyAbstract = MyFirst

x match { 
 case a: MyFirst => doSomething()
 case b: MySecond => doSomething()
 case _ => doSomethingElse()
}

Entonces me gustaría escribir algo como:

x match {
 case a @ (MyFirst | MySecond) => doSomething()
 case _ => doSomethingElse()
}

Vi una construcción similar en algún tutorial, pero me da un error:

pattern type is incompatible with expected type;
[error]  found   : object MyFirst
[error]  required: MyAbstract

Entonces, ¿hay alguna manera de definir algunos tipos diferentes en la cláusula on case? Creo que haría el código más bonito. Como si tuviera 5 de ellos, escribiré el mismo código 5 veces (llamando a doSomething ()).

¡Gracias por adelantado!


Creo que es un problema XY; tiene una superclase común para todos los doSomethingcasos, ¿por qué no coincidir con el case a : MyAbstractentonces ...?
Patryk Ćwiek

Lo siento, olvidé mencionar que tengo otras clases que amplían la clase MyAbstract y no debería llamar a doSomething.
psisoyev

Oh, está bien, solo quería aclarar eso :) Sin embargo, ahora tienes una respuesta correcta a tu problema.
Patryk Ćwiek

Respuestas:


135

Falta el paréntesis para sus clases de casos. Las clases de casos sin listas de parámetros están en desuso.

Prueba esto:

abstract class MyAbstract
case class MyFirst() extends MyAbstract
case class MySecond() extends MyAbstract

val x: MyAbstract = MyFirst()


x match {
   case aOrB @ (MyFirst() | MySecond()) => doSomething(aOrB)
   case _ => doSomethingElse()
}

Si tiene demasiados parámetros para sus clases de casos y no le gusta tener que escribir Foo(_,_,..)patrones largos , entonces tal vez:

x match {
   case aOrB @ (_:MyFirst | _:MySecond) => doSomething(aOrB)
   case _ => doSomethingElse()
}

O solo:

x match {
   case _:MyFirst | _:MySecond => doSomething(x) // just use x instead of aOrB
   case _ => doSomethingElse(x)
}

¿Pero quizás solo querías objetos de caja singleton?

abstract class MyAbstract
case object MyFirst extends MyAbstract
case object MySecond extends MyAbstract

val x: MyAbstract = MyFirst

x match {
   case aOrB @ (MyFirst | MySecond) => doSomething()
   case _ => doSomethingElse()
}

1
¿Y no hay forma de evitar los paréntesis? Como tengo algunos parámetros y se vuelve feo: case a @ (MyFirst ( , _, _, _, _) | MySecond ( , _, _, _, _)) => doSomething ()
psisoyev

9
¿Te perdiste obj @ (_: MyFirst | _: MySecond)?
Jean-Philippe Pellet

Necesito obj en los casos en los que lo estoy usando en una doSomethingllamada. En mi caso, la llamada de doSomethingno se estaba usando obj, así que no la necesito. Pero de todos modos, ¡gracias por tu comentario!
psisoyev

@ Jean-PhilippePellet De hecho, lo he hecho. Déjame editar mi publicación para agregarla.
Faiz

1
Sería bueno si la compilación fuera lo suficientemente inteligente como para encontrar el tipo común más cercano en lugar de tomar el tipo de entrada por defecto.
nilskp
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.