在Scala中如何有选择地调用函数
在Scala中,我看到了如下示例,其中如果前一个函数失败,将调用函数。但是它是如何工作的呢?例如,在下面,如果在Scala中如何有选择地调用函数,scala,Scala,在Scala中,我看到了如下示例,其中如果前一个函数失败,将调用函数。但是它是如何工作的呢?例如,在下面,如果find成功,则调用map,但如果find失败,则调用recover。从语法的角度来看,map和recover都将被调用 userService.find(id).map { user => Ok(success(user.toJson)) }.recover { case e => errors.toResult(e) // this ret
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
}
问题是
find
返回的不是User
,而是Future[User]
Future[User]
可以是DefaultPromise[User]
或never
Future
的map(..)
和recover(..)
重定向到尝试的map(..)
和恢复(..)
通过Future
的转换(..)
。对于这两种情况,变换(…)
的定义是不同的
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]
。定义了map(..)
和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(..)
forsuccess
的实现非常简单
- 当第一次呼叫失败但第二次呼叫成功时
- 当两个调用都失败时
也许你应该阅读更多关于Try
,Future
和其他单子,计算的单子链等的内容
不是有选择地调用函数,而是始终调用这些函数,但它们的职责始终相同
假设我有自己的Functor
名为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
,但它们做了它们应该做的事情
val good = Good(1000).map(_ * 2).recover { case a: Throwable => 11 }
println(good) //Good(2000)
val bad = MyFunctor.Bad[Int](new Exception("error")).map(a => a * 2).recover {
case e: Throwable => 8
}
println(bad) // Good(8)
需要记住的重要一点是,函数与任何其他数据一样都是对象。因此,您可以将一个函数传递给另一个函数,而无需实际调用它。将函数作为参数的函数称为A,有时缩写为HOF
在这种情况下,map
和recover
都是高阶函数;它们只接受一个作为函数的参数。确实执行了map
和recover
,但它们不会立即执行您赋予它们的函数。在正常使用中,如果查找
成功,将调用传递给映射
的函数;如果查找
失败,将调用传递给恢复
的函数。确切的行为取决于该find
调用返回的对象。纠正我的错误,我认为find(id)将返回您未来的[Option[user]]?或者find方法是用户定义的?返回未来[用户]或异常!我只是从SO中挑选了一个例子。但一般来说,在Scala中到处都可以看到这样的函数组合,例如map和recover in future,其中map在future返回值时调用,recover在future抛出异常时调用。如何创建这样的函数?好的,通过代码我可以推断find(id)将返回Future[User]或Future[Exception],现在您必须执行。map或onComplete或任何在Future完成后调用的回调,那么您在这段代码中有case Success或Failure,我们在失败时使用recover。