9

作为一个 Java 到 Scala 的切换器,我经常发现自己重写 null 处理的东西,比如

val itemOpt: Option[Item] = items.get(coords) // "items" is something like a Map
if (itemOpt.isDefined) {
  val item = itemOpt.get
  // do something with item, querying item fields a lot of times, for example
  if (item.qty > 10) {
    storeInVault(item.name, item.qty, coords)
  } else {
    storeInRoom(item)
  }
}

我猜它看起来很难看,它看起来真的像一段从 Java 重写的代码:

Item item = items.get(coords);
if (item != null) {
  // do something with item, querying item fields a lot of times, for example
}

它在 Java 中看起来也很丑陋,但至少少了一行。在 Scala 中处理这种简单案例的最佳实践是什么?我已经知道flatMapflatten处理 的集合Option[Stuff],并且我知道getOrElse处理默认值。我梦想着这样的事情:

items.get(coords).doIfDefined(item =>
  // do stuff with item
)

但我在OptionAPI 中看不到类似的东西。

4

4 回答 4

12

非常流行的使用模式:

val item: Option[Int] = None
val result = item map (_ + 1) getOrElse 0

因此,如果已定义,您只需使用map它来转换值。

如果您只想使用存储在 中的值Option,那么只需使用foreach

item foreach { it =>
    println(it)
}

如您所见,Option它还支持多种收集方法,因此您实际上不需要学习新的 API。您可以将其视为具有 1 个或 0 个元素的集合。

于 2012-12-18T20:59:13.263 回答
7

这应该完成您想要做的事情:

items.get(coords).foreach{ item => 
  //do stuff
}
于 2012-12-18T20:56:35.523 回答
5

检查这个托尼莫里斯帖子。当我试图理解 Option 时,它对我帮助很大。您的代码可能会以这种方式重写:

for (item <- items.get(coords)) { // "items" is something like a Map
  // do something with item, querying item fields a lot of times, for example
  if (item.qty > 10) {
    storeInVault(item.name, item.qty, coords)
  } else {
    storeInRoom(item)
  }
}
于 2012-12-19T00:06:30.567 回答
3

此外,Option 可用于带有if保护的模式匹配。我个人喜欢在这种情况下使用它,并且认为它更易于阅读。

因为mapon a Option 只有在 Option is not 时才会生效None,所以你可以先这样做,然后使用 Pattern Matching 来检查你的 itemOpt 是否是 aSomeNone

def shouldInVault(item: Item) = item.qty > 10

val itemOpt: Option[Item] = items.get(coords).map(...)

itemOpt match {
    case Some(item) if shouldInVault(item) => storeInVault(item.name, item.qty, coords)
    case Some(item) => storeInRoom(item)
    case None =>
}
于 2012-12-19T01:00:27.713 回答