返回用户(如果存在),否则在存在电子邮件地址选项时插入

时间:2017-03-13 22:48:32

标签: scala

如果我有电子邮件,我想要通过电子邮件获取用户(如果存在)。如果它不存在,我想插入并返回用户。

val userOptFut: Future[Option[User] = emailOpt.map { email =>
      userDao.getByEmail(email).map { maybeUserFut =>
        maybeUserFut match {
          case Some(u) => Future.successful(Some(u))
          case None =>
            userDao.insert(User(....)) // Future[User]
        }
      }
    }.getOrElse(Future.successful(None))

userDao.getByEmail(..)返回Future[Option[User]]

的位置

我不确定出了什么问题,但出于某种原因,它说我返回Object而不是用户。

  

Future [Object]类型的表达式不符合预期的类型   未来[选项[用户]]

以上是什么问题?

2 个答案:

答案 0 :(得分:1)

这样的嵌套真的很难在各地正确匹配类型。编译器最终做的是推断它可以使用的最具体的类型,即Object,并且与您声明的类型不匹配。

将您的功能分解为更小的部分,嵌套级别更少,这样做真的很有帮助,因此类型更难以搞定。我会这样做:

// This is very close to Future.sequence, but Option isn't a subclass
// of TraversableOnce.  There's probably an existing function to do 
// this in a library like cats or scalaz.
def toFutureOption[A](in: Option[Future[A]]): Future[Option[A]] = in match {
  case Some(fut) => fut map {Some(_)}
  case None      => Future.successful(None)
}

def getOrInsert(email: String): Future[User] =
  userDao.getByEmail(email) transformWith {
    case Success(Some(user))        => Future.successful(user)
    case Success(None) | Failure(_) => userDao.insert(User(email))
  }

val userOptFut: Future[Option[User]] =
  toFutureOption(emailOpt map getOrInsert)

答案 1 :(得分:0)

您的问题是match语句的两个分支不会返回相同的类型:

case Some(u) => u // User
case None => userDao.insert(User(....)) // Future[User]

根据您要实现的目标,您可以执行以下操作:

case Some(u) => Future.successful(Some(u))

最后的.getOrElse可能也不适合您的类型。