在Scala
中,我看到了类似于以下示例的示例,其中,如果先前的函数失败,则调用一个函数。但是它是如何工作的呢?例如,下面,如果find
成功,则调用map
,但是如果find
失败,则调用recover
。从语法角度看,map
和recover
都将被调用。
userService.find(id).map { user =>
Ok(success(user.toJson))
}.recover { case e =>
errors.toResult(e) // this returns the appropriate result
}
答案 0 :(得分:2)
不是有选择地调用函数,而是总是调用那些函数,但它们的职责是相同的,并且始终transparent。
假设我有一个名为Functor
的{{1}}和MyFunctor
和map
。
recover
:如果当前结果良好(map: A => MyFunctor[B]
),然后应用函数,否则返回替代结果A
将是recover
示例
Throwable => Myfunctor[B]
现在,您可以链接 class MyFunctor[+A] {
import MyFunctor._
def map[B](fn: A => B): MyFunctor[B] = {
this match {
case Good(a) => Good(fn(a))
case Bad(b) => Bad(b)
}
}
def recover[B >: A](fn: PartialFunction[Throwable, B]): MyFunctor[B] = {
this match {
case Bad(b) if fn.isDefinedAt(b) => Good(fn(b))
case _ => this
}
}
}
object MyFunctor {
case class Good[A](data: A) extends MyFunctor[A]
case class Bad[A](data: Throwable) extends MyFunctor[A]
}
和map
。 recover
和map
都被调用,但是它们会按其应有的方式工作。
recover
答案 1 :(得分:0)
问题是find
返回的不是User
,而是返回的Future[User]
。
Future[User]
可以是DefaultPromise[User]
或never
。
Future
的{{1}}和map(..)
通过recover(..)
的{重定向到Try
的{{1}}和map(..)
{1}}。两种情况下recover(..)
的定义也不同。
Future
https://github.com/scala/scala/blob/2.13.x/src/library/scala/concurrent/Future.scala
transform(..)
可以是transform(..)
或trait Future[+T] extends Awaitable[T] {
def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = transform(_ map f)
def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] =
transform { _ recover pf }
def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S]
//...
}
private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
override def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] = {
val p = new DefaultPromise[S]()
onComplete { result => p.complete(try f(result) catch { case NonFatal(t) => Failure(t) }) }
p.future
}
//...
}
class DefaultPromise[T] extends AtomicReference[AnyRef](Nil) with Promise[T] { /*...*/ }
final object never extends Future[Nothing] {
override def transform[S](f: Try[Nothing] => Try[S])(implicit executor: ExecutionContext): Future[S] = this
//...
}
。 Try[User]
和Failure[User]
的定义在两种情况下都不同。
Success[User]
https://github.com/scala/scala/blob/2.13.x/src/library/scala/util/Try.scala
所以基本上所有情况都可以处理:
map(..)
的{{1}}实现只是recover(..)
)也许您应该详细了解sealed abstract class Try[+T] extends Product with Serializable {
def map[U](f: T => U): Try[U]
def recover[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, U]): Try[U]
//...
}
final case class Failure[+T](exception: Throwable) extends Try[T] {
override def map[U](f: T => U): Try[U] = this.asInstanceOf[Try[U]]
override def recover[U >: T](@deprecatedName('rescueException) pf: PartialFunction[Throwable, U]): Try[U] =
try { if (pf isDefinedAt exception) Success(pf(exception)) else this } catch { case NonFatal(e) => Failure(e) }
//...
}
final case class Success[+T](value: T) extends Try[T] {
override def map[U](f: T => U): Try[U] = Try[U](f(value))
override def recover[U >: T](@deprecatedName('rescueException) pf: PartialFunction[Throwable, U]): Try[U] = this
//...
}
,recover(..)
和其他单子,计算的单子链等。
答案 2 :(得分:0)
要记住的重要一点是,函数就像其他任何数据一样都是对象。因此,您可以将一个函数传递给另一个函数,而无需实际调用它。将函数作为参数的函数称为higher-order function,有时缩写为<T>
。
在这种情况下,<dynamic>
和HOF
都是高阶函数;他们采用一个单一的参数,这是一个函数。 map
和recover
确实都已执行,但是它们不会立即执行您赋予它们的功能。在正常使用中,如果map
成功,将调用传递给recover
的函数,如果map
失败,则将传递传递给find
的函数。确切的行为取决于该recover
调用返回的对象。