6

我有一个 catch 块,我最终重复了很多次,发现这个 SO question 确认我可以使用部分函数作为 catch 块(Scala 2.9 的 try...catch 泛化的用例是什么? 1) .

目前,我的代码如下所示:

var task = newTask("update product", "update for customer " + customerId.toString)
try {
          val vcdRouter = actorSystem.actorFor("user/supervisor/router-10.10.10.10:443")

          val vdcId = new UUID("92ddba5e-8101-4580-b9a5-e3ee6ea5718f")
          val vdcGet = sendExpect[AdminVdcType](vcdRouter, GetVdc(vdcId))
          val vdcPut = VdcPutConfig(vdcGet, c)
          val vdcPutTask = sendExpect[TaskType](vcdRouter, UpdateVdc(vdcId, vdcPut))

          task = task.copy(Progress = 100, status = SuccessType)

        } catch {
          case failure: NoResponseBodyException =>
            logger.debug("*** In putCustomerProduct, got a Left(VcdGatewayException)")
            task = task.copy(Progress = 100, status = Error, Error = Option(exceptionToError(failure, BadGateway)))

          case failure: VcdGatewayException ⇒
            logger.debug("*** In putCustomerProduct, got a Left(VcdGatewayException)")
            task = task.copy(Progress = 100, status = Error, Error = Option(exceptionToError(failure, GatewayTimeout)))

          case failure: Exception ⇒
            logger.debug("*** In putCustomerProduct, got a Left(Exception)")
            task = task.copy(Progress = 100, status = Error, Error = Option(exceptionToError(failure)))

        }

由于我有这个在 catch 块内发生变化的任务 var,有没有一种很好的方法可以从包含 catch 块的部分函数中访问它?该任务是一个 var,因为它设置了一些初始化数据,例如在进入系统时创建的时间戳。我可以解决这个问题,但无论如何我都对原始问题的答案感兴趣。

4

3 回答 3

9

我假设你有几个不同var task的函数,你想使用它。

你可以创建一个函数,它同时接受task一个任务设置器作为参数,它返回一个PartialFunction你可以用作你的 catch 处理程序的函数。

def handler(task: Task, setTask: Task => Any): PartialFunction[Throwable, Any] = {
  case failure: NoResponseBodyException =>
    logger.debug("*** In putCustomerProduct, got a Left(NoResponseBodyException)")
    setTask(task.copy(Progress = 100, status = Error, Error = Option(exceptionToError(failure, BadGateway))))

  case failure: VcdGatewayException =>
    logger.debug("*** In putCustomerProduct, got a Left(VcdGatewayException)")
    setTask(task.copy(Progress = 100, status = Error, Error = Option(exceptionToError(failure, GatewayTimeout))))

  case failure: Exception =>
    logger.debug("*** In putCustomerProduct, got a Left(Exception)")
    setTask(task.copy(Progress = 100, status = Error, Error = Option(exceptionToError(failure))))
}

// somewhere else in your code...
var task = newTask("update product", "update for customer " + customerId.toString)
try {
   val vcdRouter = actorSystem.actorFor("user/supervisor/router-10.10.10.10:443")

  val vdcId = new UUID("92ddba5e-8101-4580-b9a5-e3ee6ea5718f")
  val vdcGet = sendExpect[AdminVdcType](vcdRouter, GetVdc(vdcId))
  val vdcPut = VdcPutConfig(vdcGet, c)
  val vdcPutTask = sendExpect[TaskType](vcdRouter, UpdateVdc(vdcId, vdcPut))

  task = task.copy(Progress = 100, status = SuccessType)
} catch handler(task, task = _)

我也同意user3001的观点,即您应该尝试减少 catch 处理程序中的重复。

于 2012-05-04T18:11:47.110 回答
5

这是另一种使用scala.util.control.Exception.

scala> import util.control.Exception._
import util.control.Exception._

首先创建Catch[_]对象来处理特定的异常。

scala> val nfeh = handling(classOf[NumberFormatException]) by println
nfeh: util.control.Exception.Catch[Unit] = Catch()

scala> val aobeh = handling(classOf[ArrayIndexOutOfBoundsException]) by println
aobeh: util.control.Exception.Catch[Unit] = Catch()

.or使用方法将它们组合在一起。请注意,就像在catch块中一样,顺序很重要。

scala> val h = nfeh or aobeh
h: util.control.Exception.Catch[Unit] = Catch()

将处理程序应用于可能引发异常的代码。

scala> h apply {
     |   println("1o2".toInt)
     | }
java.lang.NumberFormatException: For input string: "1o2"

scala> h apply {
     |   val x = Array(8)
     |   println(x(2))
     | }
java.lang.ArrayIndexOutOfBoundsException: 2

至于这task部分,您可以按照以下方式做一些事情:

scala> val nfeh = handling(classOf[NumberFormatException]) by { ex =>
     |   println(ex)
     |   -1
     | }
nfeh: util.control.Exception.Catch[Int] = Catch()

scala> val aobeh = handling(classOf[ArrayIndexOutOfBoundsException]) by { ex =>
     |   println(ex)
     |   -2
     | }
aobeh: util.control.Exception.Catch[Int] = Catch()

scala> val h = nfeh or aobeh
h: util.control.Exception.Catch[Int] = Catch()

scala> val task = h apply {
     |   "120".toInt
     | }
task: Int = 120

scala> val task = h apply {
     |   "12o".toInt
     | }
java.lang.NumberFormatException: For input string: "12o"
task: Int = -1

scala> val task = h apply {
     |   Array(12, 33, 22)(2)
     | }
task: Int = 22

scala> val task = h apply {
     |   Array(12, 33, 22)(6)
     | }
java.lang.ArrayIndexOutOfBoundsException: 6
task: Int = -2
于 2012-05-04T21:22:19.973 回答
2

我对 scala 很陌生,所以也许我的答案可能不是那么正确,但是:在每个“案例”块中,唯一改变的是错误类型。首先,我会为异常类型创建另一个匹配项。就像是

def exceptionToErrorReason(val failure:Exception) : ErrorReason = failure.getClass match {
  case classOf[NoResponseBodyException] => BadGateway
  case classOf[VcdGatewayException ] => GatewayTimeout
  case _ => null
}

现在你可以像这样改变你的 catch 块

case failure: Exception ⇒
        logger.debug("*** In putCustomerProduct, got a Left(" + failure.getClass().getSimpleName() + )")
        task = task.copy(Progress = 100, status = Error, Error = Option(exceptionToError(exceptionToErrorReason(failure)))

并忽略其余部分。无需复制任何东西。

于 2012-05-04T16:35:20.420 回答