2014-06-12 49 views
38

To jest pytanie o styl programowania w Swift, w szczególności Int vs UInt.Dlaczego przewodnik językowy Swift sugeruje używanie Int "nawet jeśli znane są wartości nieujemne"?

Przewodnik po języku programowania Swift zaleca programistom używanie ogólnego typu liczbowego ze znakiem Int, nawet jeśli zmienne są znane jako nieujemne. Od the guide:

Zastosowanie Uint tylko wtedy, gdy wyraźnie potrzebują unsigned całkowitą o takiej samej wielkości jak natywny słowo platformy. Jeśli tak nie jest, preferowane jest Int, nawet jeśli znane wartości nie są negatywne. Spójne użycie wartości Int dla wartości całkowitych pomaga w interoperacyjności kodu, pozwala uniknąć konwersji między różnymi typami liczb i dopasowuje wnioskowanie typu całkowitego, zgodnie z opisem w Bezpieczeństwie Typu i Wniosku Typu.

Jednak UInt będzie 32-bitowa bez znaku na 32-bitowych i 64-bitowych bez znaku w 64-bitowych architektur więc nie ma korzyści wydajność do korzystania Int nad UInt.

Natomiast Swift przewodnik daje późniejszą przykład:

let wiek = -3
assert (wiek> = 0, "wiek danej osoby nie może być mniejsza niż zero")
// powoduje to twierdzenie na spust, bo wiek nie jest> = 0

Tutaj, Runtime problem mógł być złapany na skompilować czas jeśli kod został napisany jako:

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

Istnieje wiele innych przypadkach (np niczego, co będzie indeksować zbiór), w którym za pomocą UInt by złapać problemy w czasie kompilacji zamiast wykonywania.

Pytanie więc: czy porady w języku programowania Swift Programming brzmią i czy korzyści z używania Int "nawet jeśli znane wartości nie są negatywne" przewyższają korzyści związane z bezpieczeństwem korzystania z UInt?

Dodatkowa uwaga: Po Swift używany przez kilka tygodni jego jasne, że współdziałanie z kakao wymagana jestUInt. Na przykład struktura AVFoundation używa liczb całkowitych bez znaku, gdzie wymagane jest "zliczanie" (liczba próbek/ramek/kanałów itd.). Konwersja te wartości do Int może prowadzić do poważnych błędów w których wartości są większe niż Int.max

+0

Z pewnością zależy to od tego, co uważasz za ważne. Byłbym skłonny zgodzić się z dokumentacją, że po prostu sprawia, że ​​kod jest prostszy w pracy z 'int' –

+1

@JackJames Zgadzam się, że jest to kwestia priorytetów poszczególnych programistów i kodu, nad którym pracuję. Nie widzę przekonującego przypadku w taki czy inny sposób, co sprawia, że ​​myślę, że Apple nie powinien doradzać ludziom, aby nie używali UInt, gdy sztywno trzymający się Inta mógłby spowodować, że kod złamie się na wiele nieprzyjemnych sposobów. –

+0

Tradycyjny powód zniechęcania liczb całkowitych bez znaku w C jest taki, że pętla 'for' zliczająca w dół może łatwo pójść źle; na przykład 'for (unsigned a = 10; a> 0; - a)' jest błędne, ponieważ 'a' jest * zawsze *> 0 z definicji. – alastair

Odpowiedz

1

To mówi w swoim pytaniu .. „Konsekwentne stosowanie Int dla kodu wartości całkowite AIDS interoperacyjności, unika konieczności konwersji pomiędzy różnymi typami numerycznych i dopasowuje wnioskowanie typu całkowitoliczbowego, zgodnie z opisem w Bezpieczeństwie Typu i Wniosku Typu. "

Pozwala to uniknąć problemów, takich jak przypisanie Int do UInt. Ujemne wartości Int przypisane do UIntów skutkują dużymi wartościami zamiast zamierzonej wartości ujemnej. Binarna reprezentacja obu nie odróżnia jednego typu od drugiego.

Ponadto, obie są klasami, jedna nie pochodzi od drugiej. Budowane klasy otrzymują Ints nie mogą odbierać UIntów bez przeciążania, co oznacza, że ​​konwersja między nimi byłaby częstym zadaniem UIntów, gdy większość frameworku otrzymuje Ints. Konwersja między tymi dwoma może stać się również zadaniem innym niż triwal.

Dwa poprzednie akapity mówią o "interoperacyjności" i "konwersji między różnymi typami numerów". Problemy, których należy unikać, jeśli nie używa się UInts.

+2

Racja, więc tak naprawdę chodzi o * interoperacyjność ze strukturą Swift *. Nadal uważam, że bezpieczniej jest używać liczb całkowitych bez znaku dla znanych wartości nieujemnych, ale zgadzam się, że nie ma żadnej zdrowej konwersji pomiędzy tymi dwoma typami dla wszystkich możliwych wartości każdego typu. Jeśli więc interoperacyjność jest lepsza niż bezpieczeństwo, rozumiem wybór projektu użycia Int, jeśli to możliwe. –

14

Nie sądzę, że używanie UInt jest tak bezpieczne, jak myślisz, że jest. Jak już wspomniano:

let age:UInt = -3 

powoduje błąd kompilatora. Próbowałem również:

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

, co również spowodowało błąd kompilatora. Jednak następujące (moim zdaniem o wiele bardziej powszechne w rzeczywistych programów) scenariuszy nie miał błąd kompilatora, ale faktycznie spowodowały błędy runtime EXC_BAD_INSTRUCTION:

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

jak:

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

Gdyby to było zwykły Int s, zamiast upaść, można dodać kod, aby sprawdzić warunki:

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

mogę nawet iść tak daleko, aby zrównać ich rady przeciwko używaniu UInt s do ich porady przeciwko użyciu niejawnie opakowanych opcji: Nie rób tego, chyba że masz pewność, że nie otrzymasz żadnych negatywów, ponieważ w przeciwnym razie dostaniesz błędy runtime (z wyjątkiem najprostszych przypadków).

+2

Mogłeś dodać te kontrole do sprawy "UInt" równie łatwo; wystarczy sprawdzić, czy 'num' i' a.aboveZero' to '> = 10'. – alastair

+1

Możesz także użyć klawiszy num & - 10, aby wyłączyć kontrolę przepełnienia w czasie wykonywania. –