Los tipos primitivos son los bloques básicos con los que Rust representa valores simples como números, booleanos, caracteres o agrupaciones pequeñas.
Rust es un lenguaje de tipado estático, así que el compilador necesita conocer el tipo de cada valor antes de ejecutar el programa. Muchas veces lo deduce él solito, pero conviene saber qué está deduciendo.
Enteros
Los enteros representan números sin decimales. Rust tiene enteros con signo y sin signo:
| Tipo | Rango aproximado | Uso típico |
|---|---|---|
i8, i16, i32, i64, i128 | Con negativos | Valores que pueden ser menores que cero |
u8, u16, u32, u64, u128 | Cero y positivos | Tamaños, contadores, bytes |
isize, usize | Depende de la arquitectura | Índices y tamaños de colecciones |
Por defecto, Rust usa i32 cuando escribimos un entero sin indicar nada más.
fn main() {
let edad = 42; // i32 por defecto
let puntos: u32 = 100;
let byte: u8 = 255;
}usize aparece mucho al trabajar con vectores, arrays y strings, porque es el tipo natural para índices y tamaños en memoria.
Números en coma flotante
Para números con decimales tenemos f32 y f64.
fn main() {
let temperatura = 23.5; // f64 por defecto
let sensor: f32 = 0.125;
}Por defecto, Rust usa f64, porque suele ofrecer mejor precisión y en CPUs modernas normalmente no penaliza demasiado.
Los float no son exactos. No uséis f32 o f64 para dinero si necesitáis precisión decimal estricta. Para eso hay tipos específicos o representación en enteros (céntimos, por ejemplo).
Booleanos
El tipo bool solo puede valer true o false.
fn main() {
let activo = true;
let terminado: bool = false;
}Se usa en condicionales, flags y cualquier situación donde queramos expresar sí/no, encendido/apagado o verdadero/falso.
Caracteres
El tipo char representa un carácter Unicode, no simplemente un byte.
fn main() {
let letra = 'a';
let simbolo = 'ñ';
let emoji = '🦀';
}En Rust, un char ocupa 4 bytes, porque puede representar cualquier valor Unicode válido.
Tuplas
Una tupla agrupa varios valores de tipos distintos en una sola estructura.
fn main() {
let persona = ("Luis", 42, true);
let nombre = persona.0;
let edad = persona.1;
let activo = persona.2;
}También podemos desestructurarla:
fn main() {
let punto = (10, 20);
let (x, y) = punto;
println!("x={}, y={}", x, y);
}Las tuplas son útiles para devolver varios valores pequeños sin crear todavía un struct.
Arrays
Un array guarda varios valores del mismo tipo y con longitud fija.
fn main() {
let numeros = [1, 2, 3, 4, 5];
let primero = numeros[0];
}También podemos indicar tipo y tamaño:
let sensores: [i32; 4] = [10, 20, 30, 40];Y crear un array repitiendo un valor:
let buffer = [0; 1024]; // 1024 cerosUn array no es un vector. El array tiene tamaño fijo conocido en compilación. El vector (Vec<T>) puede crecer y lo veremos más adelante.
Anotaciones de tipo
Rust infiere tipos muy bien, pero a veces necesitamos ayudarle:
fn main() {
let numero: u64 = "42".parse().expect("No era un número");
}Sin : u64, el compilador no sabría qué tipo numérico queremos obtener con parse.