usize vs u32: Duell der Integer-Typen in Rust
Wenn Sie auch nur eine Woche Rust schreiben, sind Sie dieser Situation ganz sicher schon begegnet: Der Compiler meckert, weil Sie versuchen, u32 für die Indizierung eines Vektors zu verwenden, während er usize verlangt. Oder umgekehrt – Sie übergeben usize an eine Funktion, die u32 erwartet, und bekommen eine rote Welle in der IDE.
Auf Stack Overflow hat die Frage „What's the difference between usize and u32?“ tausende Aufrufe. Das ist kein Zufall – die Verwechslung dieser Typen ist eine der häufigsten Fallen für Rust-Anfänger.
Lassen Sie uns ein für alle Mal klären, worin sie sich unterscheiden, wann man welchen verwendet und wie man Fehler vermeidet. Los geht's!
Kurz: Der Hauptunterschied
usize ist eine vorzeichenlose Ganzzahl, deren Größe von der Systemarchitektur abhängt. Auf einem 64-Bit-System sind es 8 Bytes, auf einem 32-Bit-System 4 Bytes. u32 hat immer 4 Bytes, unabhängig von der Plattform.
Aber der Unterschied liegt nicht nur in der Größe. Das Wichtigste ist die Semantik:
usizefür Größen, Indizes und die Anzahl von Elementen in Sammlungenu32für numerische Daten, die 4 Milliarden nicht überschreiten
Und ja, der Compiler erlaubt keine Vermischung ohne explizite Konvertierung. Das ist kein Bug, sondern ein Feature – so schützt Rust Sie vor Fehlern, die mit der Wortbreite der Architektur zusammenhängen.
Warum gibt es usize?
Stellen Sie sich vor, Sie schreiben Code, der sowohl auf einem alten 32-Bit-Mikrocontroller als auch auf einem modernen 64-Bit-Server laufen soll. Die Länge eines Vektors kann auf einem 32-Bit-System 2^32 - 1 Elemente nicht überschreiten, auf einem 64-Bit-System hingegen 2^64 - 1.
Wenn Sie u32 für die Indizierung auf einem 64-Bit-System verwenden würden, könnten Sie einfach nicht auf Elemente jenseits von 4 Milliarden zugreifen – selbst wenn genug Speicher vorhanden wäre. usize löst dieses Problem: Es kann immer die maximal mögliche Speichergröße der aktuellen Architektur aufnehmen.
// Beispiel: usize passt sich automatisch der Architektur anfn main() { let large_vec: Vec<u8> = vec![0; 1_000_000_000]; // 1 Milliarde Elemente // usize kann diesen Index auf jeder Plattform aufnehmen let index: usize = 999_999_999; println!("Element: {}", large_vec[index]); // u32 könnte auf einem 32-Bit-System nicht ausreichen // let bad_index: u32 = 999_999_999; // Auf 32-Bit-Systemen würde das kompilieren, aber... // large_vec[bad_index as usize]; // ...man müsste eine Konvertierung durchführen}Vergleichstabelle
| Eigenschaft | usize | u32 |
|---|---|---|
| Größe auf 64-Bit | 8 Bytes | 4 Bytes |
| Größe auf 32-Bit | 4 Bytes | 4 Bytes |
| Bereich (64-Bit) | 0 .. 2^64-1 | 0 .. 2^32-1 |
| Hauptzweck | Indizes, Größen, Längen | Numerische Daten |
| Implizite Konvertierung | Nein | Nein |
Wann sollte man usize verwenden?
Immer für die Indizierung von Sammlungen. Diese Regel hat praktisch keine Ausnahmen. Wenn Sie vec[i] schreiben, wobei i ein u32 ist, wird der Compiler sagen: „Hey, Freund, nimm doch usize“.
// Richtig: usize für Indizes verwendenfn get_element(vec: &[i32], index: usize) -> Option<&i32> { vec.get(index)}
// Falsch: u32 für die Indizierung – man muss konvertierenfn get_ele