в список импорта для модуля
>System.IO.Error
):
>handler :: IOException -> IO ()
>handler e
> | isDoesNotExistError e =
> case ioeGetFileName e of
> Just fileName -> putStrLn $ "Файл " ++ fileName ++
> " не существует!"
> Nothing -> putStrLn "Файл не существует!"
> | otherwise = ioError e
> where fileName = ioeGetFileName e
В охранном выражении, если предикат >isDoesNotExistError
вернёт значение >True
, мы использовали выражение >case
, чтобы вызвать функцию >ioeGetFileName
с параметром >e
; затем сделали сопоставление с образцом по возвращённому значению с типом >Maybe
. Выражение >case
часто используется в случаях, когда вам надо сделать сопоставление с образцом, не создавая новую функцию. Посмотрим, как это сработает:
>$ ./linecount dont_exist.txt
>Файл dont_exists.txt не существует!
Вы не обязаны использовать один обработчик для перехвата всех исключений в части кода, работающей с системой ввода-вывода. Вы можете перекрыть только отдельные части кода с помощью функции >catch
или перекрывать разные участки кода разными обработчиками, например так:
>main = do
> action1 `catch` handler1
> action2 `catch` handler2
> launchRockets
Функция >action1
использует функцию >handler1
в качестве обработчика, а функция >action2
использует >handler2
. Функция >launchRockets
не является параметром функции >catch
, так что любое сгенерированное в ней исключение обрушит нашу программу, если только эта функция не использует >try
или >catch
внутри себя для обработки собственных ошибок. Конечно же, >action1
, >action2
и >launchRockets
– это действия ввода-вывода, которые «склеены» друг с другом блоком >do
и, вероятно, определены где-то в другом месте. Это похоже на блоки >try–catch
в других языках: вы можете поместить всю вашу программу в один блок >try–catch
или защищать отдельные участки программы и перехватывать различные исключения для разных участков.
Вспомогательные функции для работы с исключениями
Ранее в этой главе мы уже познакомились с функциями >bracket
и >bracketOnError
, которые реализуют наиболее часто используемый сценарий обработки исключений, когда работа с ресурсом состоит из трёх стадий:
• получение ресурса;
• использование ресурса;
• освобождение ресурса.
В наших примерах на первой стадии открывался файл, на второй шла работа с его содержимым, а на третьей файл закрывался. Функция >bracket
гарантировала выполнение всех трёх действий, даже если в процессе генерировалось исключение, а функция >bracketOnError
запускала третье действие только в случае возникновения исключения.