В выражении с несколькими потенциально выбрасывающими вызовами где должна находиться отметка try, чтобы компилятор разрешил всё выражение?
try применяется к выражению, которое следует за ним. Если оно охватывает только один вызов, остальные потенциально выбрасывающие вызовы в той же внешней операции должны быть отмечены отдельно либо включены в явно сгруппированное выражение.
Например, в последовательном сложении вызовов безопаснее явно отметить каждый источник ошибки: try first() + try second(). Запись try (first() + second()) группирует всю операцию и позволяет одной отметке покрыть оба вызова.
Модель ошибок Swift построена вокруг явного распространения ошибки: сигнатура throws показывает, что функция может завершиться не обычным значением, а ошибкой. Отдельная отметка try делает место такого перехода заметным непосредственно в выражении.
Это решает проблему неявных исключений, когда потенциально опасный вызов трудно обнаружить при чтении кода. Компилятор проверяет, что каждый путь к выбрасывающей операции находится внутри контекста try или передаёт ошибку дальше из throws-функции.
Сложные выражения часто объединяют несколько вызовов: получение данных, преобразование и вычисление. Если разработчик мысленно распространяет одну отметку try на всю строку, но фактическая область выражения выбрана неверно, компилятор сообщит о необработанном вызове.
Неверная группировка особенно опасна при рефакторинге: добавление второго вызова в арифметическое выражение, аргументы функции или цепочку преобразований может потребовать новой отметки try. Это не runtime-ошибка, а статическая проверка, поэтому программа не соберётся до явного исправления.
try является префиксом выражения, а не универсальным разрешением на все последующие операции в строке. В записи try first() + second() оно относится к вызову first(), тогда как second() остаётся вне этого выражения и также должен быть обработан.
Группировка меняет область действия: try (first() + second()) помечает всё выражение в скобках. Такой вариант допустим, если обе операции должны иметь общий путь распространения ошибки; отдельные отметки обычно лучше показывают, какой именно вызов потенциально выбрасывает ошибку.
Минимальный пример:
В обоих выражениях ошибка любого вызова распространяется из total(), потому что сама функция объявлена с throws. Если убрать try перед second() в первом варианте, компилятор отклонит код. Скобки не перехватывают ошибку и не изменяют её тип — они только задают выражение, к которому относится try.
Это отличается от do-catch: try лишь разрешает потенциальный выброс в текущем месте, а do-catch определяет, будет ли ошибка обработана здесь или пойдёт выше. Если нужно сохранить источник ошибки и передать её вызывающему коду, предпочтительнее оставить функцию throws, а не заменять вызов на try?.
Сервис рассчитывает итоговую стоимость через два независимых вызова: загрузку базовой цены и получение скидки. Вариант с отдельными try явно показывает две точки отказа и облегчает диагностику; его минус — более многословная запись.
Группировка через try (price() - discount()) короче и полезна, когда выражение логически едино. Однако при добавлении побочных эффектов или сложной логики такая запись хуже показывает границы операций, поэтому в production-коде обычно сначала сохраняют промежуточные значения, а затем вычисляют итог.
Выбранное решение — отдельные локальные значения с отдельным try для каждого вызова. Оно позволяет легко добавить контекст, измерить длительность каждой операции и проверить, какая именно ошибка пришла, не меняя семантику распространения. Результат — прозрачный код и сохранение исходной ошибки до уровня, где принято решение о восстановлении или отображении сообщения.
try все вызовы справа от него?Нет. Он покрывает только выражение, к которому синтаксически относится. В try first() + second() второй вызов находится за пределами отмеченного вызова, поэтому для него нужна отдельная отметка или группировка всего выражения.
Нет. Скобки влияют на область выражения, но не преобразуют ошибку и не скрывают её. Любая ошибка, выброшенная внутри сгруппированного выражения, распространяется дальше с тем же значением, если её не перехватили или не преобразовали.
try на try?, чтобы упростить выражение?Технически try? превращает ошибку в отсутствие значения, но это уже изменение контракта. Оно скрывает различие между ошибкой на первом и втором вызове и может смешать ошибку с нормальным отсутствием результата, поэтому применять его следует только там, где такая потеря информации действительно предусмотрена моделью API.