web-dev-qa-db-ja.com

大規模なScalaケースクラスをパターンマッチングする方法は?

次のScalaケースクラスを考えてみましょう:

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

パターンマッチングを使用すると、次のように1つのフィールドを抽出し、他のフィールドを破棄できます。

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

私がやりたいこと、そしてケースクラスに最大20の奇数フィールドがある場合により適切なことは、WideLoad(_, _, _, _, _, some, _, _, _, thing, _, _, interesting)の入力を伴わない方法で少数の値のみを抽出することです。

次の構文は機能しませんが、名前付き引数がここで役立つことを期待していました。

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

ここに希望はありますか、それとも私はたくさんの__, _, _, __を入力するのに行き詰まっていますか?

[〜#〜] edit [〜#〜]case wl @ WideLoad(...whatever...) => wl.dを実行できることは理解していますが、それでも、必要なことを実行する簡潔な構文さえあるかどうか疑問に思っています。追加のvalを導入する必要があります。

41
Max A.

これが適切かどうかはわかりませんが、そのフィールドまたはそのフィールドのセット(テストされていないコード)に一致するようにオブジェクトを作成することもできます。

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)
}
37
Magnus

あなたはいつでも警備員に頼ることができます。それは本当にいいことではありませんが、モンスターケースクラスの通常のパターンマッチングよりも優れています:-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 doesネストされたパターンマッチングをサポート:

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! 
15
Landei

一致したパターンでタイプを指定するだけです。

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

val someVal = WideLoad(...)

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

より大きなケースクラスの要約である新しいケースクラスを作成できます

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

そして、通常どおりパターンマッチします。

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

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