Поиск по сайту:
Многих должен бояться тот, кого многие боятся (Пубилий).

Ruby — Исключения

[wtr-time]
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (2 оценок, среднее: 5,00 из 5)
Загрузка...
02.09.2018
Ruby - Исключения

Исполнение и исключение всегда работают вместе. Если вы открываете файл, которого нет, то вы не справились с этой ситуацией должным образом, ваша программа считается некорректной.

Программа останавливается, если возникает исключение. Таким образом, исключения используются для обработки различных типов ошибок, которые могут возникать во время выполнения программы, и необходимо предпринимать соответствующие действия, а не полностью останавливать программу.

Ruby обеспечивает хороший механизм обработки исключений. Мы прилагаем код, который может вызвать исключение в блоке begin/end и использовать предложения rescue, чтобы сообщить Ruby о типах исключений, которые мы хотим обработать.

Синтаксис

begin  
# -  
rescue OneTypeOfException  
# -  
rescue AnotherTypeOfException  
# -  
else  
# другие исключения
ensure
# Всегда будет выполняться
end

 

Все от begin до rescue защищено. Если во время выполнения этого блока кода возникает исключение, управление передается блоку между rescue и end.

Для каждого предложения rescue в begin Ruby сравнивает поднятое исключение с каждым из параметров по очереди. Совпадение завершится успешно, если исключение, указанное в предложении rescue, совпадает с типом создаваемого исключения или является суперклассом этого исключения.

В случае, если исключение не соответствует ни одному из указанных типов ошибок, нам разрешено использовать предложение else после всех предложений rescue.

Пример

#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "Файл успешно открыт "
   end
rescue
      file = STDIN
end
print file, "==", STDIN, "\n"

 

Это приведет к следующему результату. Вы можете видеть, что STDIN заменяется file, потому что произошла ошибка открытия.

#<IO:0xb7d16f84>==#<IO:0xb7d16f84>

Использование утверждения Retry

Вы можете захватить исключение, используя rescue, а затем использовать заявление retry для выполнения блока begin с самого начала.

Синтаксис

begin
 #Исключения в этом коде
 #поймал следующий пункт rescue
rescue
   # Этот блок будет захватывать Все типы исключений
   retry  # Это переместит управление в начало <i>begin</i>
end

Пример

#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "Файл успешно открыт"
   end
rescue
   fname = "existant_file"
   retry
end

 

Ниже приводится поток процесса:

  • Исключение произошло при открытии.
  • Вызвано rescue. fname было переназначено.
  • retry указал на начало begin.
  • Этот файл открывается успешно.
  • Продолжал необходимый процесс.
Примечание
Обратите внимание, что если файл повторно замещенного имени не существует, то этот примерный код будет повторятся бесконечно. Будьте осторожны, если вы используете повтор для процесса исключения.

Использование выражения raise

Вы можете использовать заявление raise чтобы сгенерировать исключение. Следующий метод вызывает исключение всякий раз, когда он вызывается. Будет напечатано второе сообщение.

Синтаксис

raise 

OR

raise "Error Message" 

OR

raise ExceptionType, "Error Message"

OR

raise ExceptionType, "Error Message" condition

 

Первая форма просто повторно вызывает текущее исключение (или RuntimeError, если нет текущего исключения). Используется в обработчиках исключений, которые должны перехватывать исключение, прежде чем передавать его.

Вторая форма создает новое исключение RuntimeError, устанавливая его сообщение для данной строки. Это исключение затем поднимает стек вызовов.

Третья форма использует первый аргумент для создания исключения, а затем устанавливает связанное сообщение во второй аргумент.

Четвертая форма похожа на третью форму, но вы можете добавить любой условный оператор, например, если не возбуждать исключение.

Пример

#!/usr/bin/ruby

begin  
   puts 'Код перед raise.'  
   raise 'Произошла ошибка.'  
   puts 'Код после raise.'  
rescue  
   puts 'Код в rescued.'  
end  
puts 'Код после блока begin.'

 

Это приведет к следующему результату:

Код после raise.  
Код в rescued.  
Код после блока begin.  

 

Еще один пример, показывающий использование raise:

#!/usr/bin/ruby

begin  
   raise 'Тестовое исключение.'  
rescue Exception => e  
   puts e.message  
   puts e.backtrace.inspect  
end

 

Это приведет к следующему результату:

Тестовое исключение.
["main.rb:4"]

Использование инструкции ensure

Иногда вам нужно гарантировать, что некоторая обработка выполняется в конце блока кода, независимо от того, было ли возбуждено исключение. Например, у вас может быть файл, открытый при входе в блок, и вам нужно убедиться, что он закрывается по мере выхода из блока.

Предложение ensure делает именно это. обеспечивается после последнего предложения rescue и содержит кусок кода, который всегда будет выполняться по завершении блока. Не имеет значения, нормально ли завершиться блок, если есть исключения raises и rescues, или если он завершается исключением, блок ensure будет запущен.

Синтаксис

begin 
   #.. процесс
   #..поднять исключение
rescue 
   #.. ошибка обработки 
ensure 
   #.. наконец, убедитесь в выполнении
   #.. Это всегда будет выполняться.
end

Пример

begin
   raise 'Тестовое исключение.'
rescue Exception => e
   puts e.message
   puts e.backtrace.inspect
ensure
   puts "Обеспечение выполнения"
end

 

Это приведет к следующему результату:

Тестовое исключение.
["main.rb:4"]
Обеспечение выполнения

Использование инструкции else

Если предложение else присутствует, оно выполняется после предложений rescue и до того, как оно будет выполнено.

Тело предложения else выполняется только в том случае, если в основной части кода не возникают исключения.

Синтаксис

begin 
   #.. процесс
   #.. вызывается исключение
rescue 
   # .. ошибка обработки
else
   #.. выполняется, если нет исключения
ensure 
   #.. наконец, убедитесь в выполнении
   #.. Это всегда будет выполняться.
end

 

Пример

begin
   # raise 'Тестовое исключение.'
   puts "Я не поднимаю исключение"
rescue Exception => e
   puts e.message
   puts e.backtrace.inspect
else
   puts "Поздравляем - ошибок нет!"
ensure
   puts "Обеспечение выполнения"
end

 

Это приведет к следующему результату:

Я не поднимаю исключение
Поздравляем - ошибок нет!
Обеспечение выполнения

 

Сообщение «Поднятая ошибка» можно записать с помощью переменной $!.

Catch и Throw

В то время как механизм исключения и rescue отлично подходит для отказа от выполнения, когда что-то идет не так, иногда бывает приятно выпрыгнуть из какой-то глубоко вложенной конструкции во время нормальной обработки. Это — то, где может пригодится catch и throw.

catch определяет блок, который помечен с данным именем (которое может быть символ или строка). Блок выполняется нормально до тех пор, пока не будет обнаружен throw.

Синтаксис

throw :lablename
#.. это не будет выполнено
catch :lablename do
#.. соответствующий catch будет выполняться после обнаружения throw.
end

OR

throw :lablename condition
#.. это не будет выполнено
catch :lablename do
#.. соответствующий catch будет выполняться после обнаружения throw.
end

Пример

В следующем примере используется throw для прекращения взаимодействия с пользователем, если ‘!’ набирается в ответ на любое приглашение.

def promptAndGet(prompt)
   print prompt
   res = readline.chomp
   throw :quitRequested if res == "!"
   return res
end

catch :quitRequested do
   name = promptAndGet("Имя: ")
   age = promptAndGet("Возраст: ")
   sex = promptAndGet("Пол: ")
   # ..
   # process information
end
promptAndGet("Имя:")

 

Вы должны попробовать вышеуказанную программу на своем компьютере, потому что она требует ручного взаимодействия. Это приведет к следующему результату:

Имя: Ruby on Rails
Возраст: 18
Пол: !
Имя: AndreyEx

Класс Exception

Стандартные классы и модули Ruby вызывают исключения. Все классы исключений образуют иерархию с классом Exception в верхней части. Следующий уровень содержит семь разных типов:

  • Interrupt
  • NoMemoryError
  • SignalException
  • ScriptError
  • StandardError
  • SystemExit

На этом уровне есть еще одно исключение, Fatal, но интерпретатор Ruby использует это только внутренне.

И ScriptError, и StandardError имеют ряд подклассов, но здесь нам не нужно вдаваться в подробности. Важно то, что если мы создаем собственные классы исключений, они должны быть подклассами любого класса Exception или одного из его потомков.

Давайте посмотрим на пример:

class FileSaveError < StandardError
   attr_reader :reason
   def initialize(reason)
      @reason = reason
   end
end

 

Теперь рассмотрим следующий пример, который будет использовать это исключение:

File.open(path, "w") do |file|
begin
   # Запишите данные ...
rescue
   # Что-то пошло не так!
   raise FileSaveError.new($!)
end
end

 

Важной линией здесь является поднять FileSaveError.new ($!). Мы вызываем raise, чтобы сигнализировать о том, что произошло исключение, передав ему новый экземпляр FileSaveError, по причине того, что конкретное исключение вызвало сбой записи данных.

 

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Если статья понравилась, то поделитесь ей в социальных сетях:

Читайте также

5 1 голос
Рейтинг статьи
Подписаться
Уведомить о
guest

**ссылки nofollow

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

Спасибо!

Теперь редакторы в курсе.