6

最終的にかなり繰り返すことになる catch ブロックがあり、部分関数を catch ブロックとして使用できることを確認するこの SO の質問を見つけました (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これを使用したい s が異なるいくつかの異なる機能があると仮定しています。

と task-setter の両方をパラメーターとして受け取る関数を作成できます。この関数は、catch ハンドラーとして使用できるtaskを返します。PartialFunction

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にも同意します。

于 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()

メソッドを使用してそれらを結合します.orcatchブロックと同様に、順序が重要であることに注意してください。

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 に答える