Scala for understanding futures and options

I recently read a new book by Manuel Bernhardt Jet Web Applications . In his book, he argues that Scala developers should never use .getto get an optional value.

I want to pick up his suggestions, but I try to avoid .getusing them for understanding for Futures.

Let's say I have the following code:

for {
        avatarUrl <- avatarService.retrieve(email)
        user <- accountService.save(Account(profiles = List(profile.copy(avatarUrl = avatarUrl)))
        userId <- user.id
        _ <- accountTokenService.save(AccountToken.create(userId, email))
      } yield {
        Logger.info("Foo bar")
      }

I usually used AccountToken.create(user.id.get, email)instead AccountToken.create(userId, email). However, trying to avoid this bad practice, I get the following exception:

[error]  found   : Option[Nothing]
[error]  required: scala.concurrent.Future[?]
[error]         userId <- user.id
[error]                ^

How can i solve this?

+4
source share
3 answers

First option

for, for s, :

for {
  avatarUrl <- avatarService.retrieve(email)
  user <- accountService.save(Account(profiles = List(profile.copy(avatarUrl = avatarUrl)))
} yield for {
  userId <- user.id
} yield for {
  _ <- accountTokenService.save(AccountToken.create(userId, email))
}

- Future[Option[T]] Future[T], Failure(e), e NoSuchElementException, None ( accountService.save()):

def saveWithoutOption(account: Account): Future[User] = {
  this.save(account) map { userOpt =>
    userOpt.getOrElse(throw new NoSuchElementException)
  }
}

:

(for {
  avatarUrl <- avatarService.retrieve(email)
  user <- accountService.saveWithoutOption(Account(profiles = List(profile.copy(avatarUrl = avatarUrl)))
  _ <- accountTokenService.save(AccountToken.create(user.id, email))
} yield {
  Logger.info("Foo bar")
}) recover {
  case t: NoSuchElementException => Logger.error("boo")
}

map/flatMap .

+3

:

  • A Future " ( )"
  • An Option - " "

Future[Option]? , :

[]

  • Success(Some(x)) = > . x
  • Success(None) = > , = > ,
  • Failure(_) = > - ,

Success(None) Failure(SomeApplicationException) Option .

, a Option Future for-comprehension .

def optionToFuture[T](opt:Option[T], ex: ()=>Exception):Future[T] = opt match {
   case Some(v) => Future.successful(v)
   case None => Future.failed(ex())
  }

a for-comprehension:

for {
  avatarUrl <- avatarService.retrieve(email)
  user <- accountService.save(Account(profiles = List(profile.copy(avatarUrl = avatarUrl)))
  userId <- optionToFuture(user.id, () => new UserNotFoundException(email))
  _ <- accountTokenService.save(AccountToken.create(userId, email))
} yield {
   Logger.info("Foo bar")
}
+3

Option propogation,

, id ,

for {
....
accountOpt <-
  user.id.map { id =>
    Account.create(id, ...)
  }.getOrElse {
   Future.failed(new Exception("could not create account."))
  }

...
} yield result

,

case class NoIdException(msg: String) extends Exception(msg)

invoking .get on , , Some(x) .get .

Thats .get , .

.getUse is recommended instead getOrElse.

You can mapor the flatMapopportunity to access the internal value.

Good practice

val x: Option[Int] = giveMeOption()
x.getOrElse(defaultValue)

Get can be used here.

val x: Option[Int] = giveMeOption()
x.OrElse(Some(1)).get
+1
source

Source: https://habr.com/ru/post/1654802/


All Articles