В приложении сумма элементов строится без начального значения. Как завершится выполнение этого кода и почему?
let values: [Int] = []
let total = values.reduce(+)
print(total)
Выполнение завершится аварийно во время вызова reduce(+): пустая последовательность не содержит первого элемента, который можно было бы использовать как начальное значение аккумулятора. Для пустых данных следует применять reduce с явным начальным значением, например values.reduce(0, +), что вернёт 0.
У Sequence есть две концепции свёртки. Вариант с начальным значением подходит для пустых последовательностей и позволяет явно задать тип и нейтральный элемент аккумулятора.
Вариант reduce(_:) без начального значения удобен, когда первый элемент можно использовать как начальный результат. Это уменьшает количество кода, но добавляет обязательное ограничение: последовательность должна содержать хотя бы один элемент.
В коде values.reduce(+) компилятор принимает функцию сложения как операцию объединения элементов. Однако у пустого массива нет первого элемента, с которого можно начать свёртку.
Поэтому проблема проявляется не на этапе компиляции, а во время выполнения. Если пустой результат является допустимым состоянием, такой вызов создаёт риск аварийного завершения приложения.
Вариант без начального значения концептуально работает так: первый элемент становится текущим результатом, а остальные элементы последовательно объединяются с ним. Для массива [1, 2, 3] вычисление эквивалентно ((1 + 2) + 3).
Для пустого массива первый элемент получить невозможно. Поэтому вызов reduce(_:) без начального значения завершается runtime-ошибкой, а не возвращает 0, nil или другое значение по умолчанию.
Безопасный вариант задаёт начальный результат явно:
Здесь 0 является аккумулятором до обработки элементов и нейтральным значением для сложения. Если элементы имеют другой тип или операция требует другого начального состояния, это значение также определяет тип результата и начальную семантику свёртки.
Выбор начального значения должен быть предметным. Например, для поиска максимума число 0 может быть некорректным результатом для последовательности отрицательных чисел; в таком случае лучше использовать max() и обработать возвращаемый optional либо задать корректное начальное состояние.
Сервис рассчитывает суммарную стоимость товаров в заказе. Пустой заказ допустим и должен иметь сумму 0, но разработчик использует items.reduce(+), потому что для непустых заказов выражение выглядит компактно.
Рассматривались два варианта. Вызов без начального значения короче, но аварийно завершается на пустом заказе. Вызов items.reduce(Decimal.zero, +) явно задаёт корректное состояние для пустого набора, хотя требует указать нейтральное значение.
Выбран второй вариант: он делает бизнес-правило явным и не зависит от наличия первого элемента. В результате пустые заказы обрабатываются штатно, а тип аккумулятора контролируется на уровне выражения.
Может ли reduce(+) вернуть nil для пустой последовательности?
Нет. Вариант без начального значения возвращает значение типа элемента, а не optional. У него нет значения, которым можно представить отсутствие первого элемента, поэтому пустая последовательность приводит к аварийному завершению. Если нужна безопасная модель отсутствия результата, используйте, например, values.max() или собственную проверку перед свёрткой.
Почему reduce(0, +) надёжнее не только для пустых массивов, но и для вывода типов?
Начальное значение задаёт тип результата свёртки. Это особенно важно, когда тип аккумулятора отличается от типа элементов, например при построении строки, словаря или другой структуры. Кроме того, компилятору не приходится выводить начальное состояние из первого элемента, а намерение разработчика становится явным.
Всегда ли ноль является корректным начальным значением для суммирования?
Нет. Для Int и Double ноль является нейтральным элементом сложения, но предметная модель может требовать другого поведения. Например, если отсутствие товаров должно означать «цена не рассчитана», а не числовую сумму 0, нужно вернуть optional или отдельный результат с состоянием ошибки; технически безопасная свёртка не гарантирует правильную бизнес-семантику.