考虑以下 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)
。
我希望命名参数可以在这里提供帮助,尽管以下语法不起作用:
someVal match {
case WideLoad(d = dActor) => dActor ! SomeMessage(...)
// ^---------- does not compile
}
这里还有希望吗,还是我必须打出很多很多
_, _, _, _
?
编辑:我知道我可以做到
case wl @ WideLoad(...whatever...) => wl.d
,但我仍然想知道是否有更简洁的语法可以满足我的需要,而无需引入额外的val
。
我不知道这是否合适,但您也可以构建一个对象来匹配该字段或该组字段(未经测试的代码):
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)
}
你总是可以退回到守卫身边。这不是很好,但比你的怪物案例类的正常模式匹配要好:-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!
您只需在匹配模式中指定类型即可:
case class WideLoad(a: String, b: Int, c: Float, d: ActorRef, e: Date)
val someVal = WideLoad(...)
someVal match {
case w: WideLoad => w.d ! SomeMessage(...)
}
您可以创建一个新的案例类,它是较大案例类的摘要
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(...)
}
使用 Scala 3.6.2 实验特性命名元组
scalacOptions ++= Seq("-experimental", "-language:experimental.namedTuples")
我们可以为特定案例类字段定义命名提取器,而不必像这样引用未使用的字段
someVal match {
case WideLoadActorRef(d = dActor) => dActor ! someMessage
}