2017-03-13 48 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) 
相關問題