什么时候使用哪个功能?
这是Control.Exception文档中的建议:
- 如果你想要做一些清理工作的事件将引发异常,使用
finally
,bracket
或onException
。
- 要在发生异常后恢复健康并做其他事情,最好的选择是使用其中一个
try
家庭。
- ...除非您要从异步异常中恢复,否则请使用
catch
或catchJust
。
尝试:: Exception e => IO a-> IO(ea要么)
try
采取IO
措施运行,并返回Either
。如果计算成功,则将结果包装在Right
构造函数中。(思考对与错)。如果操作引发了指定类型的异常,则将其在Left
构造函数中返回。如果异常不是适当的类型,则它将继续向上传播到堆栈。指定SomeException
为类型将捕获所有异常,这可能是一个好主意。
请注意,如果您想从纯计算中捕获异常,则必须使用evaluate
强制在中进行求值try
。
main = do
result <- try (evaluate (5 `div` 0)) :: IO (Either SomeException Int)
case result of
Left ex -> putStrLn $ "Caught exception: " ++ show ex
Right val -> putStrLn $ "The answer was: " ++ show val
catch ::例外e => IO a->(e-> IO a)-> IO a
catch
与相似try
。它首先尝试运行指定的IO
操作,但是如果引发异常,则为处理程序赋予该异常以获取替代答案。
main = catch (print $ 5 `div` 0) handler
where
handler :: SomeException -> IO ()
handler ex = putStrLn $ "Caught exception: " ++ show ex
但是,有一个重要的区别。使用catch
处理程序时,不能被异步异常(例如,通过另一个线程抛出throwTo
)中断。引发异步异常的尝试将阻塞,直到处理程序完成运行为止。
请注意,catch
Prelude中有一个不同之处,因此您可能需要这样做import Prelude hiding (catch)
。
处理::异常e =>(e-> IO a)-> IO a-> IO a
handle
只是catch
带有相反顺序的参数。使用哪种代码取决于什么使您的代码更具可读性,或者哪种代码更适合您要使用部分应用程序的情况。它们在其他方面是相同的。
尝试,捕获和处理
请注意try
,catch
和handle
将捕获指定/推断类型的所有异常。tryJust
和朋友允许您指定一个选择器功能,该功能可以过滤出您要专门处理的异常。例如,所有算术错误均为类型ArithException
。如果您只想捕捉DivideByZero
,则可以执行以下操作:
main = do
result <- tryJust selectDivByZero (evaluate $ 5 `div` 0)
case result of
Left what -> putStrLn $ "Division by " ++ what
Right val -> putStrLn $ "The answer was: " ++ show val
where
selectDivByZero :: ArithException -> Maybe String
selectDivByZero DivideByZero = Just "zero"
selectDivByZero _ = Nothing
纯度说明
请注意,这种类型的异常处理只能在不纯代码(例如IO
monad)中发生。如果需要处理纯代码中的错误,则应使用Maybe
或Either
代替(或其他代数数据类型)研究返回值。这通常是可取的,因为它更明确,因此您始终知道在什么地方会发生什么。之类的MonadControl.Monad.Error
使此类错误处理更易于使用。
也可以看看: