在.map()和.getOrElse()中使用Option

时间:2019-03-28 08:35:38

标签: scala

我正在尝试从给定键的Map[String, String]中读取一个值。 此键|值是可选的,因为它可能不存在 因此,我想使用Option,然后使用下面的mapgetOrElse来写值(如果存在),或者将其设置为一些默认值(如果不存在)。

val endpoint:String = Option(config.getString("endpoint"))
    .map(_.value())
    .getOrElse()

上面的代码失败,显示“无法从此位置访问符号值”

config是Map[String, Object]

getString是config上的一种方法,该方法接受密钥并返回值

public String getString(String key){
    <...returns value...>
}

我可以放下Option()并这样做,但是然后我必须处理getString()抛出的异常

val endpoint:String = config.getString("endpoint")

任何想法这有什么问题,或者如何解决? 更好的编写方式?

更新:我需要提到config是导入的Java库中的一个对象。不知道这是否有所作为。

2 个答案:

答案 0 :(得分:3)

如果我正确理解了您的问题,那么当不存在密钥时,config.getString将引发异常。在这种情况下,将调用包装在Option()中将无助于捕获该异常:您应该包装在Try中并将其转换为Option

Try[String]表示可以成功并成为Success(String)或失败并给您Failure(thrownException)的计算。如果您熟悉Option,则与SomeNone的两种可能性非常相似,不同之处在于Failure会包装异常,以便您了解引起此情况的原因问题。 Try(someComputation)方法将为您执行以下操作:

try {
    Success(someComputation)
} catch {
    case ex: Exception => Failure(ex)
}

要考虑的第二件事是没有价值时您真正想要发生的事情。一个明智的想法是提供默认配置,这就是getOrElse的目的:如果不给它提供默认值,就无法使用!

这里是一个例子:

val endpoint = Try(config.getString("endpoint"))
    .toOption
    .getOrElse("your_default_value")

我们可以做得更好:现在,我们正在使用Try来捕获异常,因此,如果我们要立即访问该值,则无需转换为Option。 / p>

val endpoint = Try(config.getString("endpoint")).getOrElse("your_default_value")

答案 1 :(得分:0)

您可以从这样的地图中获取值。

val m: Map[String, String] = Map("foo" -> "bar")
val res  = m.get("foo").getOrElse("N.A") 
val res2 = m.getOrElse("foo", "N.A") // same as above but cleaner

但是如果您想使用模式匹配:

val o: Option[String] = m.get("foo")
val res: String = o match { 
  case Some(value) => value
  case None => "N.A"
}

最后,一种安全的方法来处理从配置中读取的内容。

val endpoint:String = config.getString("endpoint") // this can return null
val endpoint: Option[String] = Option(config.getString("endpoint")) // this will return None if endpoint is not found

我怀疑config对象甚至可能具有类似的方法

val endpoint: Option[String] = config.getStringOpt("endpoint")

然后,您可以使用模式匹配来提取选项中的值。或众多组合器mapflatMapfold等之一

val endPoint = Option(config.getString("endpoint"))

def callEndPoint(endPoint: String): Future[Result] = ??? // calls endpoint

endPoint match { 
  case Some(ep) => callEndPoint(ep)
  case None     => Future.failed(new NoSuchElementException("End point not found"))
}

 val foo = endPoint.map(callEndPoint).getOrElse(Future.failed(new NoSuchElement...))