如何模式匹配大型Scala案例类?

时间:2010-08-13 05:24:32

标签: scala pattern-matching

考虑以下Scala案例类:

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

模式匹配允许我提取一个字段并丢弃其他字段,如下所示:

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

我想做什么,以及当一个案例类有大约20个奇数字段时更有意义的是,只提取一些不涉及输入WideLoad(_, _, _, _, _, some, _, _, _, thing, _, _, interesting)的值。

我希望命名args可以在这里提供帮助,尽管以下语法不起作用:

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

这里有什么希望吗,或者我输入很多很多_, _, _, _

编辑:我知道我可以case wl @ WideLoad(...whatever...) => wl.d,但我仍然想知道是否有更复杂的语法可以满足我的需要而无需引入额外的{{1} }。

4 个答案:

答案 0 :(得分:37)

我不知道这是否合适,但你也可以构建一个对象来匹配那个字段或那组字段(未经测试的代码):

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

答案 1 :(得分:15)

你总是可以回到守卫那里。它并不是很好,但对于你的怪物案例类比普通模式匹配更好:-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! 

答案 2 :(得分:0)

您只需在匹配的模式中指定类型:

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

val someVal = WideLoad(...)

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

答案 3 :(得分:0)

您可以创建一个新的案例类,它是较大案例类的摘要

String.Join

然后像往常一样进行模式匹配。

report.FilterString = $"orderId IN ({String.Join(", ", MyList.Select(id => $"'{id}'"))})";