Как реализовать проверку на переполнение при конвертации строки в число
Что проверяют
Понимаете ли вы, как Swift обращается с переполнением: где он вернёт nil, где уронит приложение, а где молча обернёт значение. Следом часто спрашивают, как отличить «не число» от «слишком большого числа».
Как отвечать
Начните со стандартной библиотеки. Инициализатор Int(_:) от строки проверяет переполнение сам: Int("9223372036854775808") вернёт nil, так же как Int("abc"). Пробелы по краям, дробная часть и разделители разрядов тоже дают nil, знак в начале допустим.
Проблема в том, что nil одинаковый для обоих случаев. Если ошибки нужно различать, разбирайте строку вручную с арифметикой, которая сообщает о переполнении:
multipliedReportingOverflow(by:)иaddingReportingOverflow(_:): возвращают кортеж(partialValue, overflow), приложение не падает;- накопление в отрицательную сторону:
Int.minпо модулю на единицу большеInt.max, поэтому надёжнее копить результат вычитанием и менять знак в конце, иначе строка с минимальным значением ложно даст переполнение; - проверка цифр: берите байты из
utf8в диапазоне от0x30до0x39.Character.wholeNumberValueпринимает и нелатинские цифры, например арабские; - свой тип ошибки:
enum ParseError: Error { case invalid, overflow }.
Отдельно назовите поведение арифметики. Обычные +, -, * при переполнении останавливают программу ошибкой времени выполнения, операторы &+ и &* оборачивают значение. Преобразование Int(someDouble) вне диапазона тоже падает, безопасный вариант Int(exactly:) возвращает nil.
Ввод с разделителями разрядов разбирают через IntegerFormatStyle или NumberFormatter.
Где спотыкаются
Пишут проверку number > Int.max после успешного Int(str). Условие никогда не выполнится: значение типа Int не бывает больше Int.max, а переполненная строка до этой проверки не дойдёт.
Забывают, что размер Int зависит от платформы. На Apple Watch с архитектурой arm64_32 он 32-битный, поэтому для данных с сервера надёжнее явные Int64 или Int32.
Считают, что после разбора всё безопасно, и складывают полученные значения обычным +. Сумма двух допустимых чисел переполняется и роняет приложение.