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