Scala 错误值flatMap不是可在for with Future[选项]中序列化的产品的成员
以下代码块生成失败,出现错误:Scala 错误值flatMap不是可在for with Future[选项]中序列化的产品的成员,scala,Scala,以下代码块生成失败,出现错误: value flatMap is not a member of Product with Serializable [error] if (matchingUser.isDefined) { 代码如下: for { matchingUser <- userDao.findOneByEmail(email) user <- { if (matchingUser.isDefined) { matchingUs
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
用于{
matchingUser下面是我的测试示例,用解决方案重现您的问题。
基本上,您的用户
返回关于Future的包装器(Future的选项),但它应该是Future,作为中的第一个语句,以供理解。
这就是为什么我应用了一些额外的展开。参见下面的示例
注意:它看起来不太好,我更喜欢用flatMap重写它
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
}
if
语句的第一个分支返回选项[User]
,另一个分支返回User
。因此,整个语句的结果被推断为具有可序列化的类型产品,因为它是这两个语句中唯一常见的超类型
您可以将if
中的最后一条语句包装成选项(只需执行Option(newUser)
而不是newUser
),或者更好的是,使用fold
而不是整个if(matchingUser.isDefined){…
thingy:
matchingUser.fold {
val u = new User(email)
userDao.create(u)
u
} { u =>
userDao.save(u)
u
}
这将使该语句的结果成为您可能想要的Option[User]
,但它仍然无法编译。
问题是你不能在理解中混合不同类型的单子:因为第一个单子是Future
,其他单子也必须是。你不能在那里有选项
如何解决这个问题?一种可能是让userDao.create
和userDao.save
返回他们刚刚保存的对象的未来。这可能是一种更好的做法,一般来说,比你拥有的更好,因为现在你在用户实际存储之前返回它…如果create
操作n之后失败?然后你可以像这样重写你的理解:
for {
matchingUser <- userDao.findOneByEmail(email)
user <- matchingUser.fold(userDao.create(new User(email)))(userDao.save)
} yield user
或者,在这种情况下,使用模式匹配而不是fold
看起来会更好一些:
userDao
.findOneByEmail(email)
.flatMap {
case Some(u) => userDao.save(u)
case None => userDao.create(new User(email))
}
您也可以使用部分函数语法(future1.flatMap{case Some(i)=>…
)而不是直接匹配。您在persist/update上是正确的。方法应该返回持久化/更新的记录,而不是Future[Unit]。你也说得对,如果我的代码像我发布的一样简单,那就太过分了。但实际上,我在发布之前对代码进行了大量简化,以确保我的问题直截了当,仅此而已。fold方法的另一个优点是,在你回答之前我并不知道。我会尽快接受你的答案谢谢!
userDao
.findOneByEmail(email)
.flatMap(_.fold(usrDao.create(new User(email)))(userDao.save))
userDao
.findOneByEmail(email)
.flatMap {
case Some(u) => userDao.save(u)
case None => userDao.create(new User(email))
}