Подтвердить что ты не робот

Почему руководство по языку Swift предлагает использовать Int "даже когда значения, как известно, являются неотрицательными"?

Это вопрос о стиле программирования в Swift, в частности Int vs UInt.

Руководство по языку Swift Programming Language советует программистам использовать общий целочисленный тип со знаком Int, даже если переменные известны как неотрицательные. Из руководства:

Использовать UInt только тогда, когда вам определенно нужен целочисленный тип без знака с тем же размером, что и размер родного слова платформы. Если это не так, Int является предпочтительным, даже если значения, которые необходимо сохранить, являются неотрицательными. Согласованное использование Int для целочисленных значений помогает взаимодействовать с кодами, избегает необходимости конвертировать между различными типами номеров и соответствует выводу целочисленного типа, как описано в разделе "Безопасность типа и тип".

Однако UInt будет 32-разрядным без знака в 32-разрядных архитектурах и 64-разрядных беззнаковых в 64-разрядных архитектурах, поэтому нет преимущества для производительности при использовании Int over UInt.

Напротив, руководство Swift дает более поздний пример:

пусть возраст = -3
assert (age >= 0, "возраст человека не может быть меньше нуля" )
//это вызывает утверждение, вызываемое, потому что возраст не >= 0

Здесь проблема времени выполнения может быть обнаружена во время компиляции, если код был написан как:

let age:UInt = -3  
// this causes a compiler error because -3 is negative

Есть много других случаев (например, что-либо, что будет индексировать коллекцию), где использование UInt будет ловить проблемы во время компиляции, а не во время выполнения.

Итак, вопрос: является ли совет в звуке руководства Swift Programming Language и полезны при использовании Int ", даже если значения, которые должны быть сохранены, являются неотрицательными" перевешивают преимущества безопасности использования UInt?

Дополнительная заметка: Используя Swift в течение нескольких недель, теперь ясно, что для взаимодействия с Cocoa UInt требуется. Например, инфраструктура AVFoundation использует целые числа без знака, где требуется "подсчет" (количество выборок/кадров/каналов и т.д.). Преобразование этих значений в Int может привести к серьезным ошибкам, когда значения больше, чем Int.max

4b9b3361

Ответ 1

Я не думаю, что использование UInt безопасно, как вы думаете. Как вы отметили:

let age:UInt = -3

приводит к ошибке компилятора. Я также пробовал:

let myAge:Int = 1
let age:UInt = UInt(myAge) - 3

что также привело к ошибке компилятора. Однако следующие (по моему мнению, гораздо более распространенные в реальных программах) сценарии не имели ошибки компилятора, но фактически приводили к ошибкам времени выполнения EXC_BAD_INSTRUCTION:

func sub10(num: Int) -> UInt {
    return UInt(num - 10) //Runtime error when num < 10
}
sub10(4)

а также:

class A {
    var aboveZero:UInt
    init() { aboveZero = 1 }
}
let a = A()
a.aboveZero = a.aboveZero - 10 //Runtime error

Если бы это было просто Int s, вместо сбоя вы могли бы добавить код для проверки своих условий:

if a.aboveZero > 0 {
    //Do your thing
} else {
    //Handle bad data
}

Я бы даже зашел так далеко, чтобы приравнять их советы против использования UInt к их совету против использования неявно развернутых опций: не делайте этого, если вы не уверены, что не получите никаких негативов, потому что в противном случае вы получить ошибки во время выполнения (за исключением простейших случаев).

Ответ 2

Он говорит в вашем вопросе.. "Последовательное использование Int для целочисленных значений помогает взаимодействовать с кодами, избегает необходимости конвертировать между различными типами номеров и соответствует выходу типа целочисленного типа, как описано в разделе" Безопасность типа и тип ввода ".

Это позволяет избежать таких проблем, как назначение Int для UInt. Отрицательные значения Int, назначенные UInts, приводят к большим значениям вместо предполагаемого отрицательного значения. Бинарное представление обоих не отличает один тип от другого.

Кроме того, оба являются классами, один из которых не происходит от другого. Полученные классы, получающие Ints, не могут получать UInts без перегрузки, что означает, что преобразование между ними будет общей задачей UInts, когда большая часть фреймов принимает Ints. Преобразование между ними может стать и не-тривиальной задачей.

В двух предыдущих параграфах говорится о "интероперабельности" и "преобразовании между разными типами номеров". Проблемы, которые следует избегать, если UInts не используются.