Ошибки

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

Отлов ошибок

Но одно дело натыкаться на эти ошибки во время разработки, а другое дело, когда эти ошбки видит наш конечный пользователь. Для того, чтобы нам защититься от неожиданного поведения программы существует понятие отлов ошибок. В Ruby для этого мы можем воспользоваться конструкцией begin ... end.

user_input = gets.chomp.to_i
puts 10 % user_input

простейшая программа, которая получает пользовательский ввод и делит 10 на полученное число. Но вот не задача, пользователь вводит 0, а как мы знаем, делить на 0 нельзя. В итоге получим ошибку ZeroDivisionError. Давайте исправим ситуацию:

user_input = gets.chomp.to_i
# все что находится между begin и rescue будет проверяться на ошибки
# если ошибка срабатывает, то начинает работать логика между rescue и end 
begin
  puts 10 % user_input
# после rescue мы указываем ошибку, которую мытаемся отловить
# err - объект класса ошибки которую отлавливаем
rescue ZeroDivisionError => error
  # Важно в случае ошибок не просто обработать и дать корректный ответ
  # но и не потерять информацию об ошибке, например написать ее в консоль
  p error
  puts 0
# количество отлавлиемых ошибок может быть сколько угодно
# Если ошибка не является объектом класса первой отлавливаемой ошибки, значит проверяется следующий rescue  тд.
rescue ArgumentError => error
    puts "Ошибка: Некорректный формат введенных данных. #{error.inspect}"
end
# если мы отловили ошибку, то после кода внутри rescue программа начем работать дальше
puts "finish"

В целом begin ... rescue ... end по своему виду очень похож на if ... elsif ... else ... end, только в одном случае мы проверяем условия, а в другом тип ошибки.

Создание собственных

Как Ruby выкидывает нам свою ошибку, так и мы можем выкидывать свои собственные ошибки.

Для начала создадим класс ошибки и унаследуем его от StandardError:

class MyError < StandardError
  def initialize(message)
    # любая ошибка имеет внутри себя сообщение об ошибке, которое в случае чего показывается в консоли
    # например ZeroDivisionError имеет текст "divided by 0"
    super(message)
  end
end

Теперь нам нужно выбросить эту самую ошибку

def example(arg)
  if arg > 10
    # выброс ошибки отличается от создание объекта
    # нсачала пишем raise, потом класс ошибки, потом текст, который будет передан в метод initialize
    raise MyError, "helpful description for error"
  else
    puts "It is argument - #{arg}"
  end
end

begin 
  # Сначала в консоль распечатается 'It is argument - 1'
  example(1)
  # Здесь уже сработает наша ошибка
  example(20)
# Отловили нашу ошибку
rescue MyError => error
  # Теперь в консоль напечаталось 'It is MyError - helpful description for error'
  puts "It is MyError - #{error.message}"
end

Дополнительный материал

Last updated