45 Stimmen

Wie kann man große Scala-Fallklassen nach Mustern abgleichen?

Betrachten Sie die folgende Scala-Fallklasse:

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

Der Mustervergleich ermöglicht es mir, ein Feld zu extrahieren und andere zu verwerfen, etwa so:

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

Was ich tun möchte, und was mehr relevant ist, wenn eine Fallklasse ~20 ungerade Felder hat, ist, nur ein paar Werte in einer Weise zu extrahieren, die nicht die Eingabe von WideLoad(_, _, _, _, _, some, _, _, _, thing, _, _, interesting) .

Ich hatte gehofft, dass named args hier helfen könnte, obwohl die folgende Syntax nicht funktioniert:

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

Gibt es hier irgendeine Hoffnung, oder muss ich viele, viele Zeilen abtippen? _, _, _, _ ?

EDITAR : Ich verstehe, dass ich Folgendes tun kann case wl @ WideLoad(...whatever...) => wl.d aber ich frage mich immer noch, ob es eine noch knappere Syntax gibt, die das tut, was ich brauche, ohne dass ich eine zusätzliche val .

0 Stimmen

Selbst bei 4 oder 5 Feldern machen die vielen Unterstriche das Lesen ziemlich schwierig. Eine Syntax für benannte Parameter würde die Lesbarkeit erheblich verbessern, aber soweit ich weiß, gibt es so etwas noch nicht.

0 Stimmen

Ich hatte den Eindruck, dass lange Parameterlisten im Allgemeinen zu vermeiden sind.

0 Stimmen

Sie meinten case WideLoad (d == dActor)

39voto

Magnus Punkte 1117

Ich weiß nicht, ob dies angemessen ist, aber Sie können auch ein Objekt erstellen, das nur diesem Feld oder dieser Gruppe von Feldern entspricht (nicht getesteter Code):

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

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

oder sogar

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

someVal match {
  case WideLoadBnD(b, d) => d ! SomeMessage(b)
}

17voto

Landei Punkte 53286

Sie können jederzeit auf Guards zurückgreifen. Es ist nicht wirklich schön, aber besser als normaler Musterabgleich für dich Monsterfallklassen :-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

Trotzdem sollten Sie Ihren Entwurf überdenken. Wahrscheinlich können Sie einige Parameter logisch gruppieren, indem Sie Fallklassen, Tupel, Listen, Mengen oder Maps verwenden. Scala tut unterstützen verschachtelte Mustervergleiche:

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!

1voto

vaer-k Punkte 9695

Sie können einfach den Typ in dem übereinstimmenden Muster angeben:

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

val someVal = WideLoad(...)

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

1voto

Ian Purton Punkte 14381

Sie können eine neue Fallklasse erstellen, die eine Zusammenfassung Ihrer größeren Fallklasse ist

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

Und dann Mustervergleiche wie üblich.

val someVal = WideLoadSummary(wideload.d, wideload.e)

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X