Ir al contenido

Conversión de tipos en Rust

Rust no convierte un tipo en otro automáticamente: si mezclas un i32 y un f64 en la misma expresión, no compila. Tienes que hacer la conversión tú, de forma explícita. Es a propósito: en otros lenguajes, las conversiones silenciosas son una fuente habitual de errores.

Usa la palabra clave as para convertir un tipo numérico en otro:

fn main() {
let x: i32 = 10;
let y: f64 = x as f64; // i32 -> f64
println!("{y}");
}
▶ Pruébalo tú mismo

Esto importa más de lo que parece. Si divides dos enteros sin convertirlos, obtienes una división entera en lugar del resultado con decimales que seguramente querías:

fn main() {
let a = 10;
let b = 3;
println!("{}", a / b); // 3 (división entera)
println!("{}", a as f64 / b as f64); // 3.3333333333333335
}
▶ Pruébalo tú mismo

Convertir a un tipo más pequeño puede perder datos

Sección titulada «Convertir a un tipo más pequeño puede perder datos»

Convertir de un tipo más grande a uno más pequeño (por ejemplo, de i32 a u8) no falla: simplemente recorta el valor, y el resultado puede sorprenderte:

fn main() {
let big: i32 = 300;
let small = big as u8; // u8 solo admite de 0 a 255
println!("{small}"); // 44, no 300: el valor dio la vuelta
}
▶ Pruébalo tú mismo

as funciona con algunos tipos más, además de los enteros. Cada uno tiene una regla que conviene conocer:

fn main() {
println!("{}", 3.99_f64 as i32); // 3: se cortan los decimales
println!("{}", -3.99_f64 as i32); // -3: se corta hacia el cero, no hacia abajo
println!("{}", 3.99_f64.round() as i32); // 4: redondea primero si quieres eso
println!("{}", 300.0_f64 as u8); // 255: demasiado grande, se queda en el máximo
println!("{}", -5.0_f64 as u8); // 0: demasiado pequeño, se queda en el mínimo
println!("{}", 'A' as u32); // 65: el número de código de un char
println!("{}", 97_u8 as char); // a: y de vuelta
println!("{}", true as i32); // 1 (false sería 0)
}

Salida:

3
-3
4
255
0
65
a
1
▶ Pruébalo tú mismo

Algunas ideas para llevarte:

  • De decimal a entero se descarta todo lo que hay después del punto decimal. No redondea. Llama primero a .round() si quieres el entero más cercano.
  • Los decimales fuera de rango se ajustan al valor más cercano que cabe (300.0 se convierte en 255 en un u8). Es distinto de lo que pasa con los enteros, que dan la vuelta (300 se convirtió en 44 más arriba).
  • Los caracteres tienen un número detrás (su punto de código Unicode). 'A' as u32 da 65. Solo un u8 se puede convertir directamente de vuelta a char; para números más grandes usarías char::from_u32, porque no todos los números son un carácter válido.
  • Los booleanos se convierten en 1 o 0. Al revés no funciona: 1 as bool no compila. Usa una comparación como n != 0.

as solo sirve entre tipos numéricos. Para convertir texto en un número (por ejemplo, algo que escribió el usuario), usa .parse():

fn main() {
let text = "42";
let number: i32 = text.parse().expect("no es un número válido");
println!("{}", number + 8);
}

Salida:

50
▶ Pruébalo tú mismo

.parse() puede fallar (¿y si el texto no es un número?), así que devuelve un Result en lugar del número directamente. Todavía no hemos visto Result; por ahora, .expect("mensaje") es una forma sencilla de decir “si falla, detén el programa con este mensaje”. La forma correcta de manejarlo la verás en la página Result.

En la otra dirección es más fácil: casi cualquier tipo se puede convertir en un String con .to_string():

fn main() {
let number = 42;
let text = number.to_string();
println!("{}", text + "!");
}
▶ Pruébalo tú mismo

Guarda tres notas de examen como valores i32: 7, 8 y 10. Imprime su suma y luego su media con dos decimales. Pista: si divides dos enteros obtienes 8, no 8.33, así que convierte primero la suma a f64. {:.2} imprime dos decimales.

Ver solución
fn main() {
let a: i32 = 7;
let b: i32 = 8;
let c: i32 = 10;
let sum = a + b + c;
let average = sum as f64 / 3.0; // 25.0 / 3.0, no 25 / 3
println!("suma: {sum}");
println!("media: {:.2}", average);
}

Salida:

suma: 25
media: 8.33
▶ Pruébalo tú mismo

Una tienda te da el precio como texto, "4.50", y la cantidad como un i32, 3. Convierte el texto en un f64, multiplícalo por la cantidad e imprime Total: 13.5. Pista: necesitas las dos herramientas de esta página: .parse() para el texto y as f64 para la cantidad.

Ver solución
fn main() {
let price_text = "4.50";
let quantity: i32 = 3;
let price: f64 = price_text.parse().expect("no es un precio válido");
let total = price * quantity as f64; // f64 * f64
println!("Total: {total}");
}

Salida:

Total: 13.5
▶ Pruébalo tú mismo

Sin as f64, Rust se negaría a multiplicar un f64 por un i32, porque nunca mezcla tipos numéricos por ti.

  • Rust nunca convierte tipos automáticamente: siempre conviertes de forma explícita.
  • Usa as para convertir entre tipos numéricos: x as f64, x as u8.
  • Convertir a un tipo más pequeño recorta el valor sin avisar: no da error, así que ten cuidado.
  • De decimal a entero se cortan los decimales (usa antes .round() para redondear). char y bool también se pueden convertir en números.
  • Usa .parse() para convertir texto en número, y .to_string() para lo contrario.

Comprueba lo aprendido

1. ¿Qué pasa si divides dos enteros como 10 / 3 en Rust sin convertirlos?

2. ¿Qué pasa si conviertes 300_i32 as u8?

3. Como la conversión puede fallar, ¿qué devuelve .parse() al convertir un texto en número?

Puntuación: 0 / 3