以下代码块无法构建并出现错误:
value flatMap is not a member of Product with Serializable
[error] if (matchingUser.isDefined) {
以下是代码:
for {
matchingUser <- userDao.findOneByEmail(email)
user <- {
if (matchingUser.isDefined) {
matchingUser.map(u => {
// update u with new values...
userDao.save(u)
u
})
} else {
val newUser = new User(email)
userDao.create(newUser)
newUser
}
}
} yield user
方法userDao.findOneByEmail(email) returns an
未来[选项[用户]] object.
My Google searches are only about
with
右and
左'类型。
也许我没有以正确的方式这样做,请教我如何正确地做到这一点。
答案 0 :(得分:1)
if
语句的第一个分支返回Option[User]
,另一个返回User
。因此,推断整个语句的结果具有类型Product with Serializable
,因为它是两者中唯一常见的超类型。
您可以将if
中的最后一个语句打包成Option
(只做Option(newUser)
而不是newUser
),或者更好的是,使用fold
而不是整个if(matchingUser.isDefined) {...}
东西:
matchingUser.fold {
val u = new User(email)
userDao.create(u)
u
} { u =>
userDao.save(u)
u
}
这将使该语句的结果为Option[User]
,如您所希望的那样......但它仍然无法编译。
问题在于你不能在for-comprehension中混合使用不同类型的monad:因为第一个是Future
,所以其他所有monad也必须如此。你不能在那里Option
。
如何解决这个问题?好吧,一种可能性是让userDao.create
和userDao.save
返回他们刚刚保存的对象的未来。也就是说,一般来说可能是更好的事情,那么你拥有的东西,因为现在你在用户实际存储之前返回...如果create
操作后来失败怎么办?然后你可以像这样重写你的理解:
for {
matchingUser <- userDao.findOneByEmail(email)
user <- matchingUser.fold(userDao.create(new User(email)))(userDao.save)
} yield user
或者完全摆脱它(对于像这样的简单案例来说,理解是一种矫枉过正的行为):
userDao
.findOneByEmail(email)
.flatMap(_.fold(usrDao.create(new User(email)))(userDao.save))
或者,在这种情况下,使用模式匹配而不是fold
可能看起来更好一些:
userDao
.findOneByEmail(email)
.flatMap {
case Some(u) => userDao.save(u)
case None => userDao.create(new User(email))
}
答案 1 :(得分:0)
以下是我使用解决方案重现您的问题的测试示例。
基本上你的object T {
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def future1: Future[Option[Int]] = ???
def future2(i: Int): Future[Double] = ???
for {
matchingUser <- future1
user <- {
if (matchingUser.isDefined) {
matchingUser.map { i =>
future2(i)
}
} else {
Some(future2(42))
}
} match {
case None => Future.successful(-42.0)
case Some(x) => x
}
} yield user
}
返回Future(Future of Future)的包装器,但它应该是Future,作为for-understanding的第一个声明。
这就是为什么我已经应用了一些额外展开的原因。见下面的示例。
注意:它看起来不太好,我更喜欢用flatMap地图重写它。
val userFuture = future1.flatMap {
case Some(i) => future2(i)
case None => future2(42)
}
同样用flatMap实现:
@Output() addCode = new EventEmitter<string[]>();
...
onAdd(code) {
this.addSelectedCode.push(code);
this.addCode.emit(this.addSelectedCode);
}