【问题标题】:Using Option with .map() and .getOrElse()将 Option 与 .map() 和 .getOrElse() 一起使用
【发布时间】:2019-03-28 18:30:39
【问题描述】:

我正在尝试从给定键的Map[String, String] 中读取一个值。 这个键|值是可选的,因为它可能不存在 所以,我想使用 Option 然后 map & getOrElse 如下所示写入值(如果存在),或者将其设置为默认值以防不存在。

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 库中的一个对象。不确定这是否有所作为。

【问题讨论】:

    标签: scala


    【解决方案1】:

    如果我正确理解您的问题,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

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

    【讨论】:

    • 当我尝试第一个示例时,使用 .toOptionMap(_.value) 我得到与我的代码相同的错误 - “无法从这个地方访问值”。不知何故,价值是未知的。诡异的。但是,如果我尝试第二种方式,这似乎工作得很好。
    • 当我点击 .在 map() 内部的 _ 之后,弹出的智能感知让我认为我正在处理一个字符串,因为我看到了 charAt、chars 之类的方法……。我希望在 Strings 上看到的东西。所以,这就是为什么找不到值的原因,因为字符串上没有值这样的东西。但为什么呢?
    • 我不知道你从哪里得到.map(_.value)。我们需要更多关于config 的信息,它的确切类型是什么?
    【解决方案2】:

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

    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
    

    我怀疑配置对象甚至可能有类似的方法

    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...))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-22
      • 1970-01-01
      • 2016-05-15
      • 1970-01-01
      • 2019-05-16
      • 2016-12-20
      • 1970-01-01
      相关资源
      最近更新 更多