Практическая ситуация: слой API получил Result, а вызывающий код работает через throws. Как преобразовать Result в выбрасывающий вызов без потери исходной ошибки?
Используйте метод Result.get(): при успехе он возвращает значение, а при failure выбрасывает сохранённую ошибку. В функции с throws это обычно выглядит как возврат значения через try result.get().
throws предназначен для передачи ошибки по стеку вызовов через механизм управления потоком. Result представляет тот же исход операции как обычное значение, поэтому его можно сохранить, передать или обработать позже.
Преобразование через get() позволяет соединить эти две модели без ручного дублирования логики разбора результата. Это особенно полезно на границах между callback- или value-oriented API и кодом, построенным вокруг do-catch.
Если функция должна иметь интерфейс throws, но внутри получает Result, ручной разбор через switch легко превратить в лишний шаблонный код. При неудачном преобразовании можно потерять исходный тип ошибки, заменить его общим сообщением или случайно обработать failure как обычное значение.
Важно сохранить семантику: успех должен стать возвращаемым значением, а ошибка — пройти к ближайшему подходящему catch. Иначе вызывающий код не сможет корректно классифицировать причину сбоя.
Result.get() проверяет состояние результата. Для success он возвращает связанное значение, а для failure выбрасывает объект ошибки, который был сохранён в результате.
В этом примере LoadError.offline не преобразуется в другой тип и не теряет associated value. Если loadValue() вернёт success(42), load() вернёт 42; если вернётся failure, ошибка выйдет из load() и будет доступна в catch.
Ручной switch остаётся уместным, когда нужно преобразовать одни ошибки в другие, выполнить разные действия для отдельных случаев или вернуть запасное значение. get() лучше подходит для простого перехода между моделями, когда дополнительная логика не требуется.
Клиент сетевого слоя возвращает Result<Response, NetworkError>, а доменный сервис предоставляет API throws, чтобы объединить несколько последовательных операций в одном do-catch. Вариант с ручным switch явно работает, но повторяет преобразование success и failure в каждом методе.
Можно оставить Result на всём пути, но тогда каждый вызывающий слой обязан извлекать значение самостоятельно. Это удобно для потоковой обработки и хранения результата, однако хуже сочетается с последовательным кодом, где ошибка должна немедленно прервать текущую операцию.
Выбран try result.get(): он сохраняет исходную ошибку, не добавляет лишней обёртки и позволяет единообразно обрабатывать несколько бросающих операций. Если доменному слою нужен собственный тип ошибки, преобразование выполняется отдельно в catch с сохранением исходной причины.
Меняет ли get() тип или содержимое ошибки?
Нет. При failure метод выбрасывает сохранённое значение типа Failure. Он не превращает ошибку автоматически в Error, не сериализует её и не заменяет текстовым сообщением. Поэтому pattern matching по конкретному типу ошибки в вызывающем catch сохраняет смысл.
Можно ли вызвать get() без обработки ошибки?
Только если контекст допускает выбрасывание ошибки: например, внутри функции, объявленной с throws, с использованием try, либо внутри do-catch. Сам Result не делает ошибку невыбрасывающей; get() переводит failure именно в механизм throws.
Когда switch предпочтительнее get()?
switch нужен, если преобразование не является механическим. Например, сервис может превратить .offline в доменную .serviceUnavailable, добавить контекст или для одного случая использовать резервный источник. get() следует выбирать тогда, когда требуется только передать успех дальше или пробросить исходную ошибку без изменения.