Rust-lernen.de

Datentypen in Rust

Letzte Änderung: 24.10.2023

Die Programmiersprache Rust hat eine strenge Typisierung, die Datentypen von Variablen müssen bereits zur Kompilierzeit eindeutig festgelegt sein (statische Typisierung).

Datentypen in Rust

Elementare Datentypen

Die elementaren Datentypen (auch einfache oder primitive Datentypen genannt) haben einen endlichen Wertebereich aus skalaren Werten, d.h. sie setzen sich nicht aus mehreren Werten zusammen. Rust kennt folgende elementare Datentypen:

Ganze Zahlen

BezeichnungLängeWertebereich
i88 Bit-128 bis 127
u88 Bit0 bis 255
i1616 Bit-32.768 bis 32.767
u1616 Bit0 bis 65.535
i3232 Bit-2.147.483.648 bis 2.147.483.647
u3232 Bit0 bis 4.294.967.295
i6464 Bitca. -9*1018 bis 9*1018
u6464 Bit0 bis ca. 18*1018
i128128 Bitca. -1038 bis 1038
u128128 Bit0 bis ca. 3*1038
isizeMaschinenabhängig
usizeMaschinenabhängig

Die Bitlänge der Typen isize und usize hängt von der Architektur des Computers ab, auf dem das Programm läuft. Sie beträgt beispielsweise 32 Bit auf einer 32-Bit-Architektur und 64 Bit auf einer 64-Bit-Architektur.

Zu allen oben aufgelisteten Datentypen lässt sich der jeweils kleinste und größte Wert des Wertebereichs sowie die Bitlänge über typspezifische Konstanten ermitteln. Beim Datentyp i64 wären das beispielsweise

Numerische Literale können in Rust in unterschiedlichen Notationen dargestellt werden:

DarstellungBeispiel
Dezimal1_234
Hexadezimal0xff
Oktal0o77
Binär0b1111_0000
Byte (nur u8)b'A'

Zur besseren Lesbarkeit dürfen numerische Literale das visuelle Trennzeichen _ enthalten.

Rust interpretiert numerische Literale standardmäßig als i32, wenn keine weitere Typinformation vorhanden ist. Allerdings kann man einen abweichenden Datentyp wie folgt angeben:

let a: u8 = 12;
let b     = 12u8;

Rust führt bei numerischen Literalen eine automatische Typkonvertierung durch, d.h. das Literal 12 lässt sich problemlos einer Variablen vom Typ u8 zuweisen. Bei der Zuweisung einer Variablen an eine andere Variable ist Rust hingegen strikt und führt keine automatische Typkonvertierung durch, sondern verlangt stets eine explizite Typkonvertierung (casting):

let a: u8  = 12;
let b: u16 = a;         // Typfehler!
let b: u16 = a as u16;  // Korrekt mit expliziter Typkonvertierung

Gleitkommazahlen

Gleitkommazahlen (auch Fließkommazahlen) sind Zahlen mit Komma in der Dezimalschreibweise. Rust kennt folgende zwei Typen:

BezeichnungLängeWertebereichBedeutung
f3232 Bitca. -3*1038 bis 3*1038, -∞, ∞, NaNEinfache Genauigkeit
f6464 Bitca. -10308 bis 10308, -∞, ∞, NaNDoppelte Genauigkeit

Wenn bei einem Gleitkommazahl-Literal der Typ nicht explizit angegeben ist, interpretiert es der Rust-Compiler standardmäßig als f64.

let a: f32 = 1.2;     // f32
let b      = 1.2f32;  // f32
let c      = 1.2;     // f64

Weitere elementare Datentypen

BezeichnungLängeWertebereichBedeutung
bool8 Bittrue, falseBoolescher Typ
char32 BitAlle Unicode-SkalarwerteZeichen-Typ
()0 Bit()Einheitstyp (unit type)
!0 BitNiemals-Typ (never type)

Der Datentyp char umfasst nicht nur alle gängigen alphanumerischen Zeichen auf der Tastatur, sondern auch Unicode-Sonderzeichen:

let a: char = 'A';
let b: char = '👍';
let c: char = '✅';
let d: char = '🦀';

Zusammengesetzte Datentypen

Zusammengesetzte Datentypen (auch Verbund-Typen genannt) bestehen aus mehreren skalaren Einzelwerten.

SyntaxBedeutung
[T; N]Array mit Einträgen vom Typ T und der festen Länge N.
(T),
(T, U),
(T, U, V), ...
Tupel
struct T {...}Struktur
enum T {...}Aufzählung (enum)

Beispiele:

let a: [i32; 5] = [1, 2, 3, 4, 5];
let b = a[0]; // erstes Element

let tup: (i16, f32, u8) = (500, 6.4, 1);
let (x, y, z) = tup; // Tupel destrukturieren

struct User {
    username: String,
    email: String,
}
let a = User {
    username: String::from("benutzername123"),
    email: String::from("jemand@example.com"),
};
let b = a.username; // auf einzelnes Feld zugreifen

enum IpAddrKind {
    V4(u8, u8, u8, u8),
    V6(String),
}
let home = IpAddrKind::V4(127, 0, 0, 1);
let loopback = IpAddrKind::V6(String::from("::1"));

Sonstige Datentypen

SyntaxBedeutung
fn Name(Parameter)
fn Name(Parameter) -> T
Funktion
&variable[..]Anteilstyp (slice)
&strZeichenkettenanteilstyp (string slice)
&T
&mut T
Referenz
*const T
*mut T
Roher Zeiger (unsafe)

Bei Funktionsdefinitionen muss zu jedem Parameter stets der Datentyp mit angegeben werden. Hat die Funktion einen Rückgabewert, muss auch dessen Typ angegeben werden.

Beispiele:

fn addieren(a: i64, b: i64) -> i64 {
    a + b
}
let a = addieren(5, 7); // ergibt 12

let v = vec![1, 2, 3, 4, 5];
let first = &v[0];

let a: &str = "Hallo";
let b: &str = &a[0..1]; // Teilzeichenfolge "H"

let a = String::from("Hallo");
let b = &a;       // hat den Typ &String
let mut c = String::from("Hallo");
let d = &mut c;   // hat den Typ &mut String

let a: u8 = 12;
let b: *const u8 = &a;   // roher Zeiger auf die konstante Variable a
let mut c: u8 = 13;
let d: *mut u8 = &mut c; // roher Zeiger auf die veränderbare Variable c

Quellen