Dopasowywanie wzorców wielu typów Scala

81

Zastanawiam się, jak mogę użyć dopasowania wzorców wielu typów. Mam:

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

Więc chciałbym napisać coś takiego:

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

Widziałem podobną konstrukcję w jakimś tutorialu, ale daje mi błąd:

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

Czy jest więc sposób na zdefiniowanie kilku różnych typów w klauzuli on case? Myślę, że dzięki temu kod byłby ładniejszy. Jakbym miał ich 5, napiszę ten sam kod 5 razy (wywołując doSomething ()).

Z góry dziękuję!

psisoyev
źródło
Myślę, że to problem XY; masz wspólną superklasę dla wszystkich doSomethingprzypadków, dlaczego nie dopasować case a : MyAbstractwtedy ...?
Patryk Ćwiek
Przepraszam, zapomniałem wspomnieć, że mam inne klasy, które rozszerzają klasę MyAbstract i nie powinny wywoływać metody doSomething.
psisoyev
Och, OK, chciałem tylko to wyjaśnić :) Ale teraz masz poprawną odpowiedź na swój problem.
Patryk Ćwiek
możliwy duplikat klas Dopasuj wiele przypadków w
scali

Odpowiedzi:

135

Brakuje nawiasów dla klas przypadków. Klasy przypadków bez list parametrów są przestarzałe.

Spróbuj tego:

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

Jeśli masz zbyt wiele parametrów dla klas przypadków i nie lubisz pisać długich Foo(_,_,..)wzorców, to może:

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

Lub tylko:

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

Ale może po prostu chciałeś mieć pojedyncze obiekty?

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()
}
Faiz
źródło
1
I nie ma sposobu, aby uniknąć nawiasów? Ponieważ mam kilka parametrów i robi się brzydko: case a @ (MyFirst ( , _, _, _, _) | MySecond ( , _, _, _, _)) => doSomething ()
psisoyev
9
Tęskniłeś obj @ (_: MyFirst | _: MySecond)?
Jean-Philippe Pellet,
Potrzebuję objw przypadkach, w których używam go w doSomethingrozmowie. W moim przypadku połączenie doSomethingnie było używane obj, więc go nie potrzebuję. Ale tak czy inaczej, dziękuję za komentarz!
psisoyev
@ Jean-PhilippePellet Rzeczywiście mam. Pozwól mi edytować mój post, aby go dodać.
Faiz,
1
Byłoby miło, gdyby kompilacja była wystarczająco inteligentna, aby znaleźć najbliższy wspólny typ zamiast domyślnego typu wejściowego.
nilskp,