使用scala中的选项(最佳实践)

时间:2018-06-02 22:27:02

标签: scala scala-option

我有一个方法,我写的是通过执行api调用来增加人员数据并添加丰富的数据。

所以我有这个案例类:

   case class Person(personData: PersonData, dataEnrichment: Option[DataEnrichment])

我的方法假设返回此案例类。

但之前我的过滤器很少,

如果人员身高不是"1.8 m",或者如果使用正则表达式在bio中找不到personId,我想返回Person dataEnrichment = None

我的问题是人物身高和人物身份是选项本身。

所以它看起来像这样:

   def enrichPersonObjWithApiCall(person: Person) = {

      person.personData.height.map(_.equals("1.8 m")) match {
        case Some(true) =>
          val personId = person.personData.bio flatMap { comment =>
            extractPersonIdIfExists(comment)
          }
          personId match {
            case Some(perId) =>
              apiCall(perId) map { apiRes =>
                Person(
                  person.personData,
                  dataEnrichment = apiRes)
              }
            case _ =>
              Future successful Person(
                person.personData,
                dataEnrichment = None)
          }
        case _ =>
          Future successful Person(
            person.personData,
            dataEnrichment = None)
      }
    }

    def extractPersonIdIfExists(personBio: String): Option[String] = {
      val personIdRegex: Regex = """(?<=PersonId:)[^;]+""".r
      personIdRegex.findFirstIn(personBio)
    }

    def apiCall(personId: String): Future[Option[DataEnrichment]] = {
      ???
    }

    case class DataEnrichment(res: Option[String])

    case class PersonData(name: String, height: Option[String], bio: Option[String])
剂量似乎是scala最佳实践,就像那样执行它。你有更优雅的方法来获得相同的结果吗?

3 个答案:

答案 0 :(得分:1)

使用[1-4]{0,5} 是处理for值链的好方法:

Option

这相当于一系列def enrichPersonObjWithApiCall(person: Person): Future[Person] = ( for { height <- person.personData.height if height == "1.8 m" comment <- person.personData.bio perId <- extractPersonIdIfExists(comment) } yield { apiCall(perId).map(Person(person.personData, _)) } ).getOrElse(Future.successful(Person(person.personData, None))) mapflatMap来电,但更容易阅读。

答案 1 :(得分:0)

在这里,我试图让它更具惯用性和更短:

def enrichPersonObjWithApiCall(person: Person) = {
  person.personData.height.collect {
    case h if h == "1.8 m" =>
      val personId = person.personData.bio.flatMap(extractPersonIdIfExists)

      personId.map(
        apiCall(_)
          .map(apiRes => person.copy(dataEnrichment = apiRes))
      )
  }.flatten.getOrElse(
    Future.successful(person.copy(dataEnrichment = None))
  )
}

基本上,我们的想法是在适当的时候使用mapflatMapcollect的适当的一元链而不是模式匹配。

答案 2 :(得分:0)

与Aivean的回答相同。我会使用map flatMapfilter

   def enrichPersonObjWithApiCall(person: Person) = {
     person.personData.height
       .filter(_ == "1.8 m")
       .flatMap{_=>
         val personId = person.personData.bio 
                          .flatMap(extractPersonIdIfExists)
         personId.map(
           apiCall(_)
           .map(apiRes => person.copy(dataEnrichment = apiRes))
         )
      }.getOrElse(Future.successful(person))
    }

对我来说,它更具可读性。