2011-09-13 124 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