2017-03-13 43 views
0

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

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,而不是用户。

类型未来的表达[对象]不符合预期 类型未来[选项[用户]]

什么错以上?

+0

'getOrElse(无)'?所以如果获得失败,你会返回'None'?这不符合类型'未来[选项[用户]]'(我怀疑如果获得成功,它也不符合)。 – jwvh

+0

@jwvh我更新了我的Q更新,现在它说Future [对象] – Blankman

回答

0

你的问题是,你的match语句的两个分支不返还相同种类:

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

取决于你想要达到的目的,你可以做这样的事情:

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

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

+0

我认为无部分是现在的问题,因为它是未来[用户],我需要未来[选项[用户]] – Blankman

+0

你应该添加一些变量到您的代码中,以找出您正在处理的类型。例如,为整个'userDAO ...'部分赋值val,并查看返回的是哪种类型。 'getOrElse'应该在'Option'类型上被调用。 – Tyler

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) 
相关问题