Поиск…


замечания

Исключением является объект, представляющий возникновение исключительного условия. Другими словами, это указывает на то, что что-то пошло не так.

В Ruby исключения часто упоминаются как ошибки . Это связано с тем, что базовый класс Exception существует как элемент объекта исключения верхнего уровня, но пользовательские исключения выполнения обычно являются StandardError или потомками.

Получение исключения

Чтобы повысить исключение, используйте Kernel#raise передавая класс исключения и / или сообщение:

raise StandardError # raises a StandardError.new
raise StandardError, "An error" # raises a StandardError.new("An error")

Вы также можете просто передать сообщение об ошибке. В этом случае сообщение обернуто в RuntimeError :

raise "An error" # raises a RuntimeError.new("An error")

Вот пример:

def hello(subject)
  raise ArgumentError, "`subject` is missing" if subject.to_s.empty?
  puts "Hello #{subject}"
end

hello # => ArgumentError: `subject` is missing
hello("Simone") # => "Hello Simone"

Создание настраиваемого типа исключения

Специальным исключением является любой класс, который расширяет Exception или подкласс Exception .

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

# Defines a new custom exception called FileNotFound
class FileNotFound < StandardError
end

def read_file(path)
  File.exist?(path) || raise(FileNotFound, "File #{path} not found")
  File.read(path)
end

read_file("missing.txt")  #=> raises FileNotFound.new("File `missing.txt` not found")
read_file("valid.txt")    #=> reads and returns the content of the file

Обычно можно назвать исключения, добавив в конце суффикс Error :

  • ConnectionError
  • DontPanicError

Однако, когда ошибка не требует пояснений, вам не нужно добавлять суффикс Error потому что будет избыточным:

  • FileNotFound vs FileNotFoundError
  • DatabaseExploded vs DatabaseExplodedError

Обработка исключения

Используйте блок begin/rescue чтобы поймать (спасти) исключение и обработать его:

begin
  # an execution that may fail
rescue
  # something to execute in case of failure
end

Предложение rescue аналогично блоку catch в фигуре фигурного скобки, например C # или Java.

Подобное rescue спасает StandardError .

Примечание. Следите за тем, чтобы избежать Exception вместо стандартного StandardError . Класс Exception включает SystemExit и NoMemoryError и другие серьезные исключения, которые вы обычно не хотите ловить. Всегда считайте, что вместо этого следует использовать StandardError версию StandardError (по умолчанию).

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

begin
  # an excecution that may fail
rescue CustomError
  # something to execute in case of CustomError
  # or descendant
end

Это условие спасения не будет вызывать исключения, которое не является CustomError .

Вы также можете сохранить исключение в определенной переменной:

begin
  # an excecution that may fail
rescue CustomError => error
  # error contains the exception
  puts error.message # provide human-readable details about what went wrong.
  puts error.backtrace.inspect # return an array of strings that represent the call stack
end

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

begin
   #here goes your code
rescue => e
    #failed to handle 
    raise e
end

Если вы хотите повторить свой begin блок, retry :

begin
   #here goes your code
rescue StandardError => e
   #for some reason you want to retry you code
   retry
end

Вы можете застревать в цикле, если вы поймаете исключение в каждой попытке. Чтобы этого избежать, ограничьте свой retry_count определенным количеством попыток.

retry_count = 0
begin
      # an excecution that may fail
rescue
    if retry_count < 5
        retry_count = retry_count + 1
        retry
    else
        #retry limit exceeds, do something else
    end

Вы также можете предоставить блок else или ensure блок. Блок else будет выполнен, когда begin блок завершится без исключения. ensure блок всегда будет выполняться. Блок ensure аналогичен блоку finally в фигурном языке фигурных скобок, таком как C # или Java.

begin
  # an execution that may fail
rescue
  # something to execute in case of failure
else
  # something to execute in case of success
ensure
  # something to always execute
end

Если вы находитесь в блоке def , module или class , нет необходимости использовать оператор begin.

def foo
    ...
rescue
    ...
end

Обработка нескольких исключений

Вы можете обрабатывать несколько ошибок в одном rescue декларации:

begin
  # an execution that may fail
rescue FirstError, SecondError => e
  # do something if a FirstError or SecondError occurs
end

Вы также можете добавить несколько объявлений о rescue :

begin
  # an execution that may fail
rescue FirstError => e
  # do something if a FirstError occurs
rescue SecondError => e
  # do something if a SecondError occurs
rescue => e
  # do something if a StandardError occurs
end

Порядок блоков rescue имеет значение: первое совпадение выполнено. Поэтому, если вы ставите StandardError в качестве первого условия, и все ваши исключения наследуются от StandardError , то остальные операторы rescue никогда не будут выполнены.

begin
  # an execution that may fail
rescue => e
  # this will swallow all the errors
rescue FirstError => e
  # do something if a FirstError occurs
rescue SecondError => e
  # do something if a SecondError occurs
end

Некоторые блоки имеют неявную обработку исключений, например def , class и module . Эти блоки позволяют пропустить инструкцию begin .

def foo
    ...
rescue CustomError
    ...
ensure
    ...
end

Добавление информации в (пользовательские) исключения

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

class CustomError < StandardError
  attr_reader :safe_to_retry

  def initialize(safe_to_retry = false, message = 'Something went wrong')
    @safe_to_retry = safe_to_retry
    super(message)
  end
end

Выявление исключения:

raise CustomError.new(true)

Улавливание исключения и доступ к дополнительной информации:

begin
  # do stuff
rescue CustomError => e
  retry if e.safe_to_retry
end


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow