Есть ли исключения в Go
Что проверяют
Знаете ли вы, что в Go ошибка это обычное значение, и умеете ли работать с ним дальше if err != nil. Следом почти всегда спрашивают про panic и recover и про то, как проверить ошибку после оборачивания.
Как отвечать
Исключений в привычном смысле нет: нет try/catch, и компилятор не заставляет объявлять выбрасываемые ошибки. Функция, которая может не справиться, возвращает последним значением error, интерфейс с одним методом Error() string, а вызывающий решает, что с ним делать.
- оборачивание:
fmt.Errorf("load user %d: %w", id, err)добавляет контекст и сохраняет исходную ошибку в цепочке, глагол%wпоявился в Go 1.13; - проверка:
errors.Is(err, sql.ErrNoRows)для sentinel-ошибок иerrors.As(err, &target)для своих типов. Оба проходят по всей цепочке; - несколько ошибок:
errors.Joinи несколько%wв одномErrorfдоступны с Go 1.20; - panic: для ситуаций, когда продолжать нельзя, и для ошибок программиста. Рантайм сам паникует при выходе за границы слайса, записи в nil-map, разыменовании nil-указателя;
- recover: срабатывает только внутри отложенной функции и только в той же горутине. Так
net/httpловит панику в обработчике, чтобы один запрос не уронил весь сервер.
Хорошо добавить, зачем так сделано: путь ошибки виден в коде, нет скрытых переходов через десяток фреймов. Плата за это многословность, и честно назвать её тоже плюс к ответу.
Где спотыкаются
Говорят, что recover в main поймает панику из любой горутины. Нет: паника в горутине без собственного recover роняет весь процесс. А fatal error: concurrent map writes не перехватывается вообще.
Сравнивают ошибки через == после оборачивания. Проверка err == ErrNotFound перестаёт срабатывать, как только кто-то добавил контекст через %w, нужен errors.Is.
Возвращают типизированный nil: функция отдаёт var e *MyErr = nil как error, и err != nil оказывается истинным, потому что в интерфейсе лежит тип. Возвращать нужно явный nil.