首页 > 解决方案 > 从Option [String]中提取值的scala方式是什么?

问题描述

我正在尝试从 Option[String] 中提取辅助和 event_type 提取这些值的最佳 scala 方法是什么,如果没有,则将 null 作为输出。

val payload = Some({"event":"testApi",
    "data":[{"aid":"test","pr":"{\"id\":\"813da0e5-d9aa-4275-b9d4-5e84362b73bb\",\"event_type\":\"promo app loaded\",\"label\":\"beach apartheid\",\"total\":1,\"timestamp\":1617891494152}}]",
    "tv":"js-2.17.3"
    })

如果我有这个如何提取其他然后如果其他。

标签: scala

解决方案


这取决于您之后将如何处理此有效负载。Option是一个monad,所有标准操作,如.map, flatMap, .foreach,.filter等都.collect适用于它。我真的建议您阅读scala monads以更好地处理它。

简而言之,你应该构建你的代码,这样你就不需要做任何事情option.get来访问实际值,几乎从不做option.isEmpty(或者option.nonEmpty,如果曾经做的话,也很少做.getOrElse(例如val unwrappedJson = payload.getOrElse('{}'))。

在大多数情况下,我也会避免模式匹配,尽管该书在另一个答案中提到了这一点。它可能是“最常见的”,但在大多数情况下不是“最好的”(虽然,这开始进入“个人品味”领域,模式匹配在技术上没有任何问题,只是它不是“单子的” ",因此在视觉上更难阅读和解析)。

您可以做的一些事情的例子:

    def parsePayload(maybePayload: Option[String]): Option[Payload] = 
       maybePayload.map(json.readValue[Payload])
   
    ...
    
    def getLabels(maybePayload: Option[String]): Seq[String] = maybePayload
        .map(json.readValue[Payload])
        .toSeq
        .flatMap(_.data)
        .map(_.pr.label)


    ...

    def uniqueIds(maybePayload: Option[String]): Seq[String] = maybePayload
       .map(json.readValue[Payload])
       .toSeq
       .flatMap(_.data)
       .map(_.pr.id)
       .distinct

    ...


    def maybeData(maybePayload: Option[String]): Seq[Data] = 
       parsePayload(maybePayload)
         .fold(Seq.empty[Data])(_.data)

    ...


    def byId(maybePayload: Option[String]): Map[String, Seq[Data]] = maybePayload
       .map(json.readValue[Payload])
       .toSeq
       .flatMap(_.data)
       .groupBy(_.pr.id)
       .map { case(id, datas) => datas }
       
    def forId(maybePayload: Option[String], id: String): Seq[Data] = maybePayload
       .map(json.readValue[Payload])
       .toSeq
       .flatMap(_.data.filter(_.pr.id == id))
     ...

    def forId2(maybePayload: Option[String], id: String): Seq[Data] = 
       byId(maybePayload).getOrElse(id)

    ...

    def maxTotal(maybePayload: Option[String]): Option((String, Int)) = 
      parsePayload(maybePayload)
      .collect { case Payload(_, data, _) if data.nonEmpty => data.maxBy(_.pr.total) }
      .map { case data => data.pr.id -> data.pr.total }
         
    ...  

 
    def printPayload(maybePayload: Option[String]): Unit = 
       maybePayload.foreach(println)

等等。


推荐阅读