2011-09-13 70 views
3

我使用util.control.Exception.catching內部異常轉換爲具體到我的庫中的異常類型:使用捕捉(...)可以避免重複投擲Throwable嗎?

import util.control.Exception._ 

abstract class MyException extends Exception 

case class ErrorOccurredDuringFoo(e : Exception) extends MyException 

def foo : Foo = { 
    catching(classOf[Exception]) either { fooInternals } match { 
     case Left(e) => throw ErrorOccurredDuringFoo(e) 
     case Right(v) => v 
    } 
} 

不幸的是,這是行不通的。應用由either返回的Catch不返回Either[Exception,Foo],它返回Either[Throwable,Foo]。但我已經告訴catching我希望它只捕獲Exception的子類型,而不是全部Throwable s,並且在內部它已經匹配Exception

我正確使用它?難道我不能說服catching返回它捕獲的異常作爲我要求它捕獲的異常類的一個實例嗎?我最好只是添加一個冗餘asInstanceOf[Exception]?我寧願不能,如果我可以避免它,因爲catching實例可以邏輯地在其他地方創建,並且如果我有一天將其更改爲catching[Throwable]而不更改ErrorOccurredDuringFoo而不是在演員陣容時發生運行時錯誤,我想要編譯錯誤到Exception失敗。

回答

4

Catch未在Throwable上進行參數化,僅限於結果類型。向下轉型中的Throwable類型的唯一方法是使用mkCatcher方法:

val c = catching[Foo](
    mkCatcher(
    (t: Throwable) => t.getClass == classOf[MyException], 
    (e: MyException) => throw new ErrorOccurredDuringFoo(e))) 
c(fooInternals) 

但是,Catch需要Catcher[T] - 這真的只是一個PartialFunction[Throwable, T]的別名。

作爲一個case語句PartialFunction我們可以使用模式匹配:

val c: Catcher[Foo] = { 
    case e: MyException => throw new ErrorOccurredDuringFoo(e) 
} 
catching(c)(fooInternals) 
+0

謝謝!這最終會更好。 – Ben

1

你可以寫這樣的:

def foo : Foo = { 
    catching(classOf[Exception]) either { fooInternals } match { 
     case Left(e: Exception) => throw ErrorOccurredDuringFoo(e) 
     case Right(v) => v 
    } 
} 

有趣的是,它不抱怨失蹤案件。

+0

這很有趣。雖然它最終相當於運行時downcast,但如果'classOf [Exception]'改爲'classOf [Throwable]',編譯器將不會靜態地知道'Case Left(e:Exception)'是錯誤的,並且結果將是運行時匹配錯誤。 – Ben