当前位置: 动力学知识库 > 问答 > 编程问答 >

playframework - Unexpected scala.MatchError

问题描述:

I have a method with the following definition :

def userPosts(userId: String): Future[List[Post]]

I would like to have a method which returns cached date or calls userPosts if there is no cached data. I've prepared something like this:

def cachedUserPosts(userId: String): Future[List[Post]] = {

for {

cached <- bucket.get[List[Post]]("posts_" + userId)

} yield {

cached match {

case Some(list) => list

case None => userPosts(userId) match {

case list:List[Post] => list

}

}

}

}

I have an error:

[error] play - Cannot invoke the action, eventually got an error: scala.MatchError: [email protected] (of class scala.concurrent.impl.Promise$DefaultPromise)

play.api.Application$$anon$1: Execution exception[[MatchError: [email protected] (of class scala.concurrent.impl.Promise$DefaultPromise)]]

at play.api.Application$class.handleError(Application.scala:296) ~[play_2.11-2.3.6.jar:2.3.6]

at play.api.DefaultApplication.handleError(Application.scala:402) [play_2.11-2.3.6.jar:2.3.6]

at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [play_2.11-2.3.6.jar:2.3.6]

at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [play_2.11-2.3.6.jar:2.3.6]

at scala.Option.map(Option.scala:145) [scala-library-2.11.2.jar:na]

Caused by: scala.MatchError: [email protected] (of class scala.concurrent.impl.Promise$DefaultPromise)

at models.Post$$anonfun$fastUserPosts$1.apply(Post.scala:130) ~[classes/:na]

at models.Post$$anonfun$fastUserPosts$1.apply(Post.scala:126) ~[classes/:na]

at scala.util.Success$$anonfun$map$1.apply(Try.scala:236) ~[scala-library-2.11.2.jar:na]

at scala.util.Try$.apply(Try.scala:191) ~[scala-library-2.11.2.jar:na]

at scala.util.Success.map(Try.scala:236) ~[scala-library-2.11.2.jar:na]

2015-07-26 19:33:24.211 INFO net.spy.memcached.auth.AuthThread: Authenticated to 192.168.10.42/192.168.10.42:11210

Do you have any idea what's going on?

网友答案:

You are pattern matching on a Future, if we try an analogous pattern match in the console :

val p = Promise[Int]
val f = p.future
p.success(5) // fulfill the promise

Pattern matching on f gives us :

scala> f match { case i: Int => i }
<console>:15: error: pattern type is incompatible with expected type;
 found   : Int
 required: scala.concurrent.Future[Int]
              f match { case i: Int => i }
                                ^

Your userPosts function returns a Future[List[Post]] and you can't pattern match on the future directly to get the List[Post]. You can find more information on working with Future on the Scala website.

Lets fix your cachedUserPosts function. Your version could also be written as (does not compile):

bucket.get[List[Post]]("posts_" + userId) map ( cached => cached match {
  // List[Post] in Future.map => Future[List[Post]]
  case Some(list) => list
  // userPosts already gives us a Future[List[Post]]
  // We could have used Await.result(userPosts(userId), 5.seconds)
  // to get the List[Post] from the Future, but then we would be blocking
  case None => userPosts(userId)
})

If we convert the map into a flatMap we can return a Future[List[Post]], but then we would also need to return a Future[List[Post]] in the Some case, which can easily be done using Future.successful :

bucket.get[List[Post]]("posts_" + userId) flatMap ( cached => cached match {
  // List[Post] to Future[List[Post]] using Future.successful
  case Some(list) => Future.successful(list)
  case None => userPosts(userId)
})

We could clean this up a little bit, by using map/getOrElse instead of pattern matching on the Option :

def cachedUserPosts(userId: String): Future[List[Post]] =
  bucket.get[List[Post]]("posts_" + userId).flatMap { cached =>
     cached.map(list => Future.successful(list))
           .getOrElse(userPosts(userId))
  }
分享给朋友:
您可能感兴趣的文章:
随机阅读: