Scala кілька типів збігу шаблонів


80

Мені цікаво, як я можу використовувати збіг декількох типів. Я маю:

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

Тому я хотів би написати щось на зразок:

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

Я бачив подібну конструкцію в якомусь підручнику, але це призводить до помилки:

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

Тож чи є спосіб визначити кілька різних типів у реченні on case? Я думаю, це зробить код гарнішим. Як ніби у мене їх буде 5, я напишу один і той же код 5 разів (викликаючи doSomething ()).

Спасибі заздалегідь!


Я думаю, що це проблема XY; у вас є загальний суперклас для всіх doSomethingвипадків, чому б не відповідати case a : MyAbstractтодішньому ...?
Patryk Ćwiek

Вибачте, забув згадати, що у мене є інші класи, які розширюють клас MyAbstract і не повинні викликати doSomething.
псісоєв

О, добре, просто хотів це пояснити :) Хоча зараз у вас є правильна відповідь на вашу проблему.
Patryk Ćwiek,

можливий дублікат класів Match multiple
case

Відповіді:


135

Вам бракує дужок для класів кейсів. Класи випадків без списків параметрів застаріли.

Спробуйте це:

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

Якщо у вас занадто багато параметрів для класів кейсів і вам не подобається писати довгі Foo(_,_,..)шаблони, то можливо:

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

Або просто:

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

Але, можливо, ви просто хотіли одиничні об'єкти регістру?

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
І немає можливості уникнути дужок? Оскільки у мене є кілька параметрів, і це стає потворним: case a @ (MyFirst ( , _, _, _, _) | MySecond ( , _, _, _, _)) => doSomething ()
psisoyev

9
Ви сумували obj @ (_: MyFirst | _: MySecond)?
Жан-Філіп Пелле

Мені потрібно objу випадках, коли я використовую це у doSomethingдзвінку. У моєму випадку дзвінок doSomethingне використовувався obj, тому мені це не потрібно. Але в будь-якому випадку, дякую за ваш коментар!
псісоєв

@ Jean-PhilippePellet Справді, я маю. Дозвольте мені відредагувати свою публікацію, щоб додати її.
Faiz

1
Було б непогано, якби компіляція була досить розумною, щоб знайти найближчий загальний тип, а не за замовчуванням тип введення.
nilskp
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.