我正在尝试在当前项目中尽可能多地使用 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) }