这种方法是有效的:
val schoolFuture = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- schoolStore.getSchool(sid.get) if sid.isDefined
} yield s
然而我不太满意其中的 "if",似乎我应该能够使用地图(map)来代替。
但是当我尝试使用地图(map):
val schoolFuture: Future[Option[School]] = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- sid.map(schoolStore.getSchool(_))
} yield s
我遇到了编译错误:
[error] found : Option[scala.concurrent.Future[Option[School]]]
[error] required: scala.concurrent.Future[Option[School]]
[error] s <- sid.map(schoolStore.getSchool(_))
我尝试了几种变体,但都没有找到合适的解决方案。有人能建议一个更好的理解方法和/或解释我的第二个示例存在何问题吗?
这里是一个最小但完整的可运行示例,使用Scala 2.10:
import concurrent.{Future, Promise}
case class User(userId: Int)
case class UserDetails(userId: Int, schoolId: Option[Int])
case class School(schoolId: Int, name: String)
trait Error
class UserStore {
def getUserDetails(userId: Int): Future[Either[Error, UserDetails]] = Promise.successful(Right(UserDetails(1, Some(1)))).future
}
class SchoolStore {
def getSchool(schoolId: Int): Future[Option[School]] = Promise.successful(Option(School(1, "Big School"))).future
}
object Demo {
import concurrent.ExecutionContext.Implicits.global
val userStore = new UserStore
val schoolStore = new SchoolStore
val user = User(1)
val schoolFuture: Future[Option[School]] = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- sid.map(schoolStore.getSchool(_))
} yield s
}
import scala.reflect.runtime.universe._; def typeme[A: TypeTag](a: A) = { println(implicitly[TypeTag[A]]); a }
,你可以让Scala 2.10打印出表达式的类型,然后将表达式包装在typeme
中,例如:sid = typeme(ud.right.toOption.flatMap(_.schoolID))
。 - Rex KerrOptionIsFuture
,我认为它类似于一个monad transformer。 - ps_ttf