Согласование с шаблоном нескольких типов в 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

Итак, есть ли способ определить несколько разных типов в предложении case? Думаю, это сделало бы код красивее. Как будто у меня их будет 5, я напишу один и тот же код 5 раз (вызов doSomething ()).

Заранее спасибо!


Я думаю, это проблема XY; у вас есть общий суперкласс для всех doSomethingслучаев, почему бы не сопоставить case a : MyAbstractthen ...?
Patryk 27wiek

Извините, забыл упомянуть, что у меня есть другие классы, которые расширяют класс MyAbstract и не должны вызывать doSomething.
псисоев

О, хорошо, просто хотел прояснить это :) Но теперь у вас есть правильный ответ на вашу проблему.
Patryk 27wiek

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

Ответы:


135

Вам не хватает скобок для классов case. Классы case без списков параметров устарели.

Попробуй это:

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

Если у вас слишком много параметров для ваших классов case и вам не нравится писать длинные 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)
}

Но, возможно, вам просто нужны одноэлементные объекты case?

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.