defer в Go: порядок вызовов, аргументы и ранний return

defer откладывает вызов функции до завершения окружающей функции. Несколько отложенных вызовов выполняются в обратном порядке: последний зарегистрированный — первым. Обычный ранний return не отменяет уже зарегистрированные defer.

Аргументы отложенного вызова вычисляются в момент выполнения инструкции defer; это отличается от чтения переменной внутри замыкания позже.

Короткий пример

package main

import "fmt"

func main() {
    defer fmt.Println("первый")
    defer fmt.Println("второй")
    fmt.Println("работа")
}

Результат:

работа
второй
первый

В цикле отложенные вызовы накапливаются до выхода из функции, а не до конца итерации. Не переносите это правило на аварийное завершение процесса через os.Exit: отложенные функции при нём не выполняются.

Попробуйте самостоятельно

Ниже — отдельное задание с другими данными. Напишите решение и запустите проверку кода без регистрации. Для последовательного обучения откройте курс.

Документация.

Закрытие запущенных этапов

Когда сложная операция разбивается на несколько последовательных этапов, каждый из них требует аккуратного завершения — вне зависимости от того, чем закончился весь процесс. Пропустить закрытие хотя бы одного этапа значит оставить систему в неопределённом состоянии, поэтому порядок завершения не менее важен, чем порядок запуска.

Пользователь задаёт количество этапов, которые нужно запустить последовательно. Каждый запущенный этап немедленно ставится в очередь на закрытие, и эта очередь раскручивается строго в обратном порядке: последний запущенный закрывается первым. Именно такая симметрия гарантирует, что ни один этап не окажется открытым после завершения работы.

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

Что уже дано

Программа получает число этапов и выводит запуск каждого этапа в цикле.

Что нужно сделать

Допишите stopStages. При допустимом числе от 1 до 3 регистрируйте через defer закрытие каждого уже запущенного этапа. При выходе закрытия должны появиться в обратном порядке. Одно финальное сообщение сеанс завершён обязано появиться и при раннем возврате обычной ошибки. Для недопустимого числа верните errors.New("некорректное число этапов"); panic использовать нельзя.

Ввод и вывод

Программа читает одно целое число из stdin. Она печатает запуск этапов, затем отложенные закрытия и итоговую строку.

Пример

Ввод
3
Вывод
запустить этап 1
запустить этап 2
запустить этап 3
закрыть этап 3
закрыть этап 2
закрыть этап 1
сеанс завершён
результат: успешно
РешениеGo

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Связанные задачи