Scala:根据模式匹配有条件地在 Map 定义中添加元素



我正在尝试在当前项目中尽可能多地使用 Scala 功能,但我很难在 Map 定义中使用模式匹配。

为了说明这一点,请考虑以下代码片段:

class Foo(val element: Option[Any], val element2: Any, ...)
val bar = new Foo(...)
val map = Map(bar.element match {
case None => ??? // Do not add an item here
case Some(el) => "element" -> el
}, "element2" -> element2, ...
)

我在此代码片段中遇到的问题是None情况。如何指定不应在此处添加任何元素?

我尝试了几件事:

  • 我不能在这里介绍{},因为它会被解释为Unit
  • 简单地在case None =>后留下一个空白会导致类型不匹配;因为它也被认为是一种Unit,而我们需要一个Tuple2
  • 我可以在Map定义之后执行模式匹配,只在Some(el)的情况下添加一个元素。但是,这感觉不是一种非常优雅的方式。
  • 我可以完全省略case None =>,但这会产生警告,因为匹配并不详尽,如果元素确实None,则会失败。

如果我想涵盖 Map 定义中的所有情况,我如何指示在None的情况下,不应添加任何元素?

一些上下文:我将其用作某种类型的 (akka) spray json 协议定义的一部分,并想知道是否有一种速记方法可以做到这一点,而无需有条件地向地图添加元素。

提前感谢!

编辑:建议的解决方案

根据 mavarazy 的回答,我通过如下所示的代码解决了这个问题:

class Foo(val element: Option[Any], val element2: Any, ...)
val bar = new Foo(...)
val map = Map(bar.element match {
case None => "" -> null // Do not add an item here
case Some(el) => "element" -> el
}, "element2" -> element2, ...
).filter(_._2 != null)

从来没有想过这样做,但我认为它仍然有些优雅。谢谢!

在选项 3 上,您可以通过将 .map 替换为接收部分函数的 .collect 来删除 None 情况

从我的角度来看,选项 3 没有错,但如果你不喜欢它,你也可以这样做:

val map = Map(
"element" -> element,
"element2" -> Option(element2)
).
filter(_._2.isDefined).
mapValues(_.get)

如果这是您的问题之一,它还将阻止您在element2中使用null值进行Map

使用"collect"将是我的偏好,因为它需要一个部分函数,即只收集那些与部分函数中指定的模式匹配的值 -

val map: Map[String, Option[String]] = Map(
"element" -> Some("element"),
"element2" -> Some("element2"),
"element3" -> None
)
map collect { case (s, Some(e)) => (s, e) }

最新更新