Исполнение и исключение всегда идут вместе. Если вы открываете файл, который не существует, то если вы не справились с этой ситуацией должным образом, значит, ваша программа плохого качества.
Программа останавливается, если возникает исключение. Таким образом, исключения используются для обработки ошибок различного типа, которые могут возникнуть во время выполнения программы и предпринять соответствующие действия вместо полной остановки программы.
Ruby предоставляет хороший механизм для обработки исключений. Мы заключаем код, который может вызвать исключение, в начало / конец блока и используем спасательные предложения, чтобы сообщить Ruby типы исключений, которые мы хотим обработать.
Синтаксис
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
else
# Other exceptions
ensure
# Always will be executed
end
Все от начала до спасения защищено. Если во время выполнения этого блока кода возникает исключение, управление передается в блок между спасением и завершением .
Для каждого пункта спасения в блоке начала Ruby сравнивает возбужденное исключение с каждым из параметров по очереди. Сопоставление будет успешным, если исключение, указанное в предложении восстановления, совпадает с типом создаваемого в данный момент исключения или является суперклассом этого исключения.
В случае, если исключение не соответствует ни одному из указанных типов ошибок, мы можем использовать предложение else после всех предложений спасения .
пример
Live Demo
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
file = STDIN
end
print file, "==", STDIN, "\n"
Это даст следующий результат. Вы можете видеть, что STDIN заменяется на файл, потому что открыть не удалось.
#<IO:0xb7d16f84>==#<IO:0xb7d16f84>
Использование оператора повтора
Вы можете перехватить исключение, используя блок восстановления, а затем использовать оператор retry для запуска блока begin с самого начала.
Синтаксис
begin
# Exceptions raised by this code will
# be caught by the following rescue clause
rescue
# This block will capture all types of exceptions
retry # This will move control to the beginning of begin
end
пример
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
fname = "existant_file"
retry
end
Ниже приведен поток процесса —
Исключение произошло при открытии.
Пошел спасать. Fname был переназначен.
По повторным попыткам пошли к началу начала.
На этот раз файл открывается успешно.
Продолжение необходимого процесса.
ПРИМЕЧАНИЕ. — Обратите внимание, что если файл с замененным именем не существует, этот пример кода повторяется бесконечно. Будьте осторожны, если вы используете повтор для процесса исключения.
Использование рейза Statement
Вы можете использовать оператор поднятия, чтобы вызвать исключение. Следующий метод вызывает исключение всякий раз, когда он вызывается. Это второе сообщение будет напечатано.
Синтаксис
raise
OR
raise "Error Message"
OR
raise ExceptionType, "Error Message"
OR
raise ExceptionType, "Error Message" condition
Первая форма просто повторно вызывает текущее исключение (или RuntimeError, если нет текущего исключения). Это используется в обработчиках исключений, которым необходимо перехватить исключение перед его передачей.
Вторая форма создает новое исключение RuntimeError , устанавливая его сообщение в заданную строку. Это исключение затем поднимается вверх по стеку вызовов.
Третья форма использует первый аргумент для создания исключения, а затем устанавливает связанное сообщение со вторым аргументом.
Четвертая форма похожа на третью форму, но вы можете добавить любое условное утверждение, например, если только не вызвать исключение.
пример
#!/usr/bin/ruby
begin
puts 'I am before the raise.'
raise 'An error has occurred.'
puts 'I am after the raise.'
rescue
puts 'I am rescued.'
end
puts 'I am after the begin block.'
Это даст следующий результат —
I am before the raise.
I am rescued.
I am after the begin block.
Еще один пример, показывающий использование рейза —
Live Demo
#!/usr/bin/ruby
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
end
Это даст следующий результат —
A test exception.
["main.rb:4"]
Используя обеспечить заявление
Иногда вам нужно гарантировать, что некоторая обработка выполняется в конце блока кода, независимо от того, было ли вызвано исключение. Например, у вас может быть файл, открытый при входе в блок, и вам нужно убедиться, что он закрывается при выходе из блока.
Пункт гарантии делает именно это. гарантированно идет после последнего предложения спасения и содержит кусок кода, который всегда будет выполняться после завершения блока. Не имеет значения, если блок завершается нормально, если он вызывает и спасает исключение, или если он завершается неперехваченным исключением, будет запущен блок обеспечения .
Синтаксис
begin
#.. process
#..raise exception
rescue
#.. handle error
ensure
#.. finally ensure execution
#.. This will always execute.
end
пример
Live Demo
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
ensure
puts "Ensuring execution"
end
Это даст следующий результат —
A test exception.
["main.rb:4"]
Ensuring execution
Использование else Statement
Если присутствует условие else , оно идет после пунктов спасения и перед любой гарантией .
Тело предложения else выполняется только в том случае, если основная часть кода не вызывает никаких исключений.
Синтаксис
begin
#.. process
#..raise exception
rescue
# .. handle error
else
#.. executes if there is no exception
ensure
#.. finally ensure execution
#.. This will always execute.
end
пример
Live Demo
begin
# raise 'A test exception.'
puts "I'm not raising exception"
rescue Exception => e
puts e.message
puts e.backtrace.inspect
else
puts "Congratulations-- no errors!"
ensure
puts "Ensuring execution"
end
Это даст следующий результат —
I'm not raising exception
Congratulations-- no errors!
Ensuring execution
Поднятое сообщение об ошибке может быть записано с помощью $! переменная.
Поймать и бросить
Несмотря на то, что механизм исключений при поднятии и спасении отлично подходит для отказа от выполнения, когда что-то идет не так, иногда приятно иметь возможность выпрыгнуть из глубоко вложенной конструкции во время обычной обработки. Это где ловить и бросать пригодится.
Функция catch определяет блок, помеченный данным именем (это может быть Symbol или String). Блок выполняется нормально, пока не встретится бросок.
Синтаксис
throw :lablename
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
OR
throw :lablename condition
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
пример
В следующем примере команда throw завершает взаимодействие с пользователем, если ‘!’ набирается в ответ на любое приглашение.
def promptAndGet(prompt)
print prompt
res = readline.chomp
throw :quitRequested if res == "!"
return res
end
catch :quitRequested do
name = promptAndGet("Name: ")
age = promptAndGet("Age: ")
sex = promptAndGet("Sex: ")
# ..
# process information
end
promptAndGet("Name:")
Вы должны попробовать вышеуказанную программу на вашем компьютере, потому что она требует ручного взаимодействия. Это даст следующий результат —
Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby
Исключение класса
Стандартные классы и модули Ruby порождают исключения. Все классы исключений образуют иерархию с классом Exception вверху. Следующий уровень содержит семь различных типов —
Прерывание
NoMemoryError
SignalException
Ошибка скрипта
Стандартная ошибка
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
# Write out the data ...
rescue
# Something went wrong!
raise FileSaveError.new($!)
end
end
Важной строкой здесь является повышение FileSaveError.new ($!) . Мы вызываем функцию указывает, что произошло исключение, передавая ему новый экземпляр FileSaveError, причём причина в том, что конкретное исключение вызвало сбой записи данных.