Как сопоставить шаблон с большими классами случаев Scala? - PullRequest
38 голосов
/ 13 августа 2010

Рассмотрим следующий класс дел Scala:

case class WideLoad(a: String, b: Int, c: Float, d: ActorRef, e: Date)

Сопоставление с образцом позволяет мне извлечь одно поле и удалить другие, например:

someVal match {
    case WideLoad(_, _, _, d, _) => d ! SomeMessage(...)
}

То, что я хотел бы сделать, и что более важно, когда класс case имеет ~ 20 нечетных полей, - это извлечь только несколько значений таким образом, чтобы не вводить WideLoad(_, _, _, _, _, some, _, _, _, thing, _, _, interesting).

Я надеялся, что именованные аргументы могут здесь помочь, хотя следующий синтаксис не работает:

someVal match {
    case WideLoad(d = dActor) => dActor ! SomeMessage(...)
    //              ^---------- does not compile
}

Есть ли надежда здесь, или я застрял, набирая много-много _, _, _, _?

РЕДАКТИРОВАТЬ : я понимаю, что могу сделать case wl @ WideLoad(...whatever...) => wl.d, но я все еще задаюсь вопросом, есть ли еще более краткий синтаксис, который делает то, что мне нужно, без необходимости вводить дополнительный val.

Ответы [ 3 ]

37 голосов
/ 13 августа 2010

Я не знаю, подходит ли это, но вы также можете создать объект, просто соответствующий этому полю или этому набору полей (непроверенный код):

object WideLoadActorRef {
  def unapply(wl: WideLoad): Option[ActorRef] = { Some(wl.d) }
}

someVal match {
  case WideLoadActorRef(d) => d ! someMessage
}

или даже

object WideLoadBnD {
  def unapplySeq(wl: WideLoad): Option[(Int,ActorRef)] = { Some((wl.b,wl.d)) }
}

someVal match {
  case WideLoadBnD(b, d) => d ! SomeMessage(b)
}
15 голосов
/ 13 августа 2010

Вы всегда можете вернуться к охранникам. Это не очень хорошо, но лучше, чем обычное сопоставление с образцом для ваших классов монстров: -P

case class Foo(a:Int, b:Int, c:String, d:java.util.Date)

def f(foo:Foo) = foo match {
  case fo:Foo if fo.c == "X" => println("found")
  case _ => println("arrgh!")
}

f(Foo(1,2,"C",new java.util.Date())) //--> arrgh!
f(Foo(1,2,"X",new java.util.Date())) //--> found

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

case class Bar(a: Int, b:String)
case class Baz(c:java.util.Date, d:String)
case class Foo(bar:Bar, baz:Baz)

def f(foo:Foo) = foo match {
   case Foo(Bar(1,_),Baz(_,"X")) => println("found")
   case _ => println("arrgh!")
}

f(Foo(Bar(1,"c"),Baz(new java.util.Date, "X"))) //--> found
f(Foo(Bar(1,"c"),Baz(new java.util.Date, "Y"))) //--> arrgh! 
0 голосов
/ 14 ноября 2018

Вы можете просто указать тип в совмещенном шаблоне:

case class WideLoad(a: String, b: Int, c: Float, d: ActorRef, e: Date)

val someVal = WideLoad(...)

someVal match {
    case w: WideLoad => w.d ! SomeMessage(...)
}
...