В отладочном слое нужно записать успешное значение Result, не меняя ни значение, ни ошибку: какой метод применить и чем он отличается от преобразующего комбинатора?
Используйте метод Result::inspect. Он получает ссылку на успешное значение, выполняет побочный эффект и возвращает исходный Result без изменения его типа, значения или ошибки. В отличие от map, inspect не преобразует успешное значение.
Комбинаторы Result появились как способ последовательно описывать обработку ошибок без повторяющихся конструкций match. Для операций наблюдения, журналирования и диагностики преобразование значения не требуется, поэтому отдельный метод позволяет выразить побочный эффект явно и сохранить цепочку обработки неизменной.
Такой подход поддерживает разделение обязанностей: основная цепочка отвечает за вычисление результата, а inspect — за наблюдение за ним.
Если для журналирования успешного результата использовать map, замыкание должно вернуть значение, которое станет новым успешным результатом. Это может случайно изменить тип, значение или смысл цепочки, особенно если побочный эффект добавляется только для диагностики.
Ручной match решает задачу, но увеличивает объём кода и требует отдельно сохранять оба варианта Result. Неправильное размещение побочного эффекта может также привести к журналированию не тех данных или к выполнению действия не в том месте цепочки.
inspect вызывается только для варианта Ok. Замыкание получает ссылку на успешное значение, поэтому оно может его прочитать, но не забирает владение. После выполнения замыкания метод возвращает исходный Result<T, E>.
Вызов map имеет другую семантику: его замыкание преобразует T в U, поэтому результат становится Result<U, E>. inspect предназначен именно для наблюдения и не меняет T.
Метод не делает обработку ошибок: для Err его замыкание не запускается, а ошибка передаётся дальше без изменений. Побочный эффект выполняется в момент вычисления цепочки, поскольку методы Result не являются ленивыми. Если замыкание внутри inspect вызовет panic, это будет обычная паника, а не преобразование в Err.
Сервис загружает конфигурацию и хочет записывать в журнал успешный идентификатор, сохраняя возможность передать ошибку вызывающему коду через ?.
Вариант с match наиболее явно контролирует поведение, но многословен. Вариант с map может сработать, если замыкание вернёт исходное значение, однако он смешивает наблюдение с преобразованием и усложняет поддержку. Вариант с inspect лучше выражает намерение: значение только читается для журнала, а результат остаётся прежним.
Поэтому выбирается inspect. Если загрузка завершается Err, запись об успешном идентификаторе не появляется, а исходная ошибка продолжает обработку без изменений. Если загрузка успешна, идентификатор журналируется, после чего тот же Result можно передать дальше или обработать оператором ?.
Запустится ли замыкание inspect, если результат содержит Err?
Нет. inspect выполняет замыкание только для Ok. При Err метод сразу возвращает исходный результат, поэтому использовать inspect для журналирования ошибок нельзя; для этого предназначен соответствующий метод наблюдения за ошибкой, inspect_err.
Почему замыкание inspect получает ссылку, а не само успешное значение?
Потому что задача метода — наблюдать результат, а не передавать владение значением. Благодаря ссылке значение остаётся внутри Result и доступно последующим операциям цепочки. Если требуется преобразовать или переместить успешное значение, нужно использовать преобразующий метод, например map, с соответствующими последствиями для типа и владения.
Что произойдёт при размещении inspect перед оператором ? в цепочке?
Сначала inspect выполнит замыкание, если текущий результат равен Ok. Затем оператор ? либо извлечёт успешное значение и продолжит выполнение, либо немедленно вернёт ошибку из функции. Для Err замыкание inspect не выполняется, поэтому побочный эффект не должен быть единственным механизмом обработки ошибки.