работа с опциями в scala (лучшие практики) - PullRequest
0 голосов
/ 03 июня 2018

У меня есть метод, который я написал для обогащения персональных данных, выполнив вызов API и добавив обогащенные данные.

поэтому у меня есть этот класс дел:

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

мой метод предполагает возвращение этого класса дел.

, но у меня есть несколько фильтров раньше,

в случае, если рост лица не равен "1.8 m" ИЛИ, если personId не был найден в био с использованием регулярного выражения, я хочу вернуть Person с dataEnrichment = None

моя проблема в том, что рост лица и personId являются самими параметрами.

так это выглядит так:

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

dosent, похоже, лучшая практика для такого выполнения.У вас есть более элегантный способ получить тот же результат?

Ответы [ 3 ]

0 голосов
/ 03 июня 2018

Та же идея, что и у ответа Айвея.Просто я бы использовал map flatMap и filter.

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

Это более читабельно для меня.

0 голосов
/ 03 июня 2018

Использование 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)))

Это эквивалентно цепочке вызовов map, flatMap и filter,но намного легче читать.

0 голосов
/ 03 июня 2018

Здесь я попытался сделать его более идиоматичным и короче:

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

По сути, идея состоит в том, чтобы использовать соответствующие монадические цепочки map, flatMap, collect вместо сопоставления с образцомкогда уместно.

...