При каком условии функция с rethrows может завершиться ошибкой?
Функция с rethrows может передать ошибку вызывающему коду только тогда, когда ошибка возникла внутри переданной ей замыкающей функции или другого разрешённого источника, зависящего от этой замыкания. Она не может произвольно выбросить собственную ошибку независимо от переданного замыкания.
Обычный throws описывает безусловную возможность функции завершиться ошибкой. Это надёжно, но для функций высшего порядка слишком грубо: функция может лишь вызывать переданное замыкание и не добавлять собственных причин сбоя.
rethrows нужен для точного выражения такого контракта: функция сама не создаёт ошибки, а только пропускает наружу ошибку переданного ей throwing-замыкания. Благодаря этому API сохраняет информацию о реальной причине необходимости обработки ошибки.
Представим универсальную функцию-обёртку, которая выполняет переданную операцию, добавляет измерение времени или логирование и возвращает её результат. Если объявить такую функцию как throws, вызывающий код будет обязан использовать обработку ошибок даже при передаче безопасного, не выбрасывающего замыкания.
Если скрыть ошибку внутри обёртки, вызывающий код потеряет исходную причину сбоя или получит искусственную ошибку. Если позволить обёртке выбрасывать ошибки независимо от операции, её контракт станет шире, чем фактическое поведение.
rethrows проверяется компилятором. Вызов функции с невыбрасывающим замыканием не требует обработки ошибки, а вызов с выбрасывающим замыканием требует try и дальнейшей передачи или перехвата ошибки.
В первом вызове замыкание не может выбросить ошибку, поэтому execute также не создаёт обязательства по обработке ошибки. Во втором случае ошибка может возникнуть в load, и execute передаёт её дальше без изменения.
Функция с rethrows не должна напрямую выбрасывать собственную ошибку в независимой ветке. Нельзя использовать rethrows как более мягкую форму throws: если функция сама формирует ошибки, следует объявлять её как throws.
rethrows не преобразует ошибки, не классифицирует их и не заменяет Result. Он только уточняет связь между возможностью ошибки обёртки и возможностью ошибки переданного вызываемого объекта. Если требуется вернуть ошибку как значение, сохранить её для последующей обработки или передать через границу асинхронного API, обычно выбирают Result или другую подходящую модель.
В SDK есть функция, которая выполняет пользовательскую операцию и записывает длительность выполнения. Операция может быть как чистой и безопасной, так и сетевой, выбрасывающей ошибку.
Вариант с throws прост и понятен, но заставляет каждый вызов обёртки выглядеть потенциально ошибочным, даже если передана безопасная операция. Вариант с перехватом внутри обёртки позволяет унифицировать журналирование, но требует решить, как сохранять исходную ошибку, и может нарушить ожидаемый контракт вызывающего кода.
Выбран rethrows: обёртка не добавляет собственных причин сбоя и только передаёт ошибку операции. В результате безопасные вызовы остаются простыми, а сетевые вызовы сохраняют обычную семантику throws, включая исходный тип и значение ошибки.
rethrows выбросить ошибку из собственной проверки аргументов?Нет, если эта ошибка не связана с переданным throwing-замыканием. Например, проверка входного значения с последующим throw означает, что функция сама является источником ошибки; для неё нужен throws. rethrows допускает только условную передачу ошибок, возникающих через разрешённые вызываемые параметры.
rethrows, если функцию всегда можно объявить как throws?throws корректен, но менее точен: он переносит обязанность обработки ошибки на каждый вызов. rethrows сохраняет условность контракта и позволяет компилятору учитывать фактический тип переданной операции. Это особенно важно для универсальных функций высшего порядка, где безопасные и выбрасывающие замыкания должны использоваться единообразно без лишнего синтаксиса.
rethrows на Result без изменения поведения API?Нет. rethrows сохраняет модель управления потоком через механизм ошибок Swift: ошибка передаётся по стеку вызовов и обрабатывается через do-catch, try или дальнейший throws. Result представляет успех или ошибку как обычное значение, поэтому меняет способ композиции, хранения и передачи результата. Выбор зависит от контракта API: для синхронной прозрачной обёртки над throwing-операцией подходит rethrows, а для явной передачи результата как данных — Result.