Сопоставление шаблонов на больших / длинных классах case

есть ли более читаемый и более надежный (для рефакторинга) способ соответствовать классам case, как это ?

пример

Класс Case

очень длинный класс case со многими "полями".

case class Data(name: String, time: Long, ..., userId: Option[UUID] ..., orders: Int, ... ) //more fields fields more

шаблон матча: вариант a

строительство. Но подвержены ошибкам при изменении положения полей. Один заканчивается подсчетом _.

res match {
  case data@Data(_,_,_,_,_,_,Some(id),_,_,_,6,_,_) => (id, data.orders)
  case _ => ... 

} 

шаблон матча: вариант b

работает также. Устойчив к изменению заказов. Получает действительно громоздко с большим количеством проверок в охране. Также чтение значения должно быть повторено.

res match {
  case data: Data if data.userId.isDefined && data.orders == 6 => (data.userId.get,data.orders)
  case _ => ...
} 

вопрос перефразировать

есть ли способ объединить варианты A и B, чтобы получить выгоду от обоих подходов ?

2 ответов


Вы можете использовать специальный экстрактор:

res match {
  case ExtractUserIdAndOrders(Some(id), 6) => ...
  case _ => ...
}

здесь

object ExtractUserIdAndOrders {
  def unapply(data: Data) = Some((data.userId, data.orders))
}

Вы можете определить его внутри метода, Если вам это нужно только один раз, или в широком масштабе для нескольких подобных матчей.


пока нет unapply метод в области, который принимает параметр из типа, которому вы соответствуете, вы можете определить пользовательский экстрактор для этого, например

case class Big(foo: String, bar: String, baz: Option[String], x: Int, y: Int)

object SmallerBig {
  def unapply(x: Big): Option[(Option[String], Int)] = Some(x.baz, x.y)
}

val x = Big("a", "b", Some("c"), 1, 2)

x match {
  case Big(_, _, _, _, _) =>
  case SmallerBig(Some(a), b) =>
}

возвращаемый тип метода unapply не должен быть Option, но тип, который вы возвращаете, должен предоставить методы get и isDefined.