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.
Convertir entre tipos numéricos con as
Sección titulada «Convertir entre tipos numéricos con as»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}");}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}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}Convertir decimales, caracteres y booleanos
Sección titulada «Convertir decimales, caracteres y booleanos»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-34255065a1Algunas 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.0se convierte en255en unu8). Es distinto de lo que pasa con los enteros, que dan la vuelta (300se convirtió en44más arriba). - Los caracteres tienen un número detrás (su punto de código Unicode).
'A' as u32da65. Solo unu8se puede convertir directamente de vuelta achar; para números más grandes usaríaschar::from_u32, porque no todos los números son un carácter válido. - Los booleanos se convierten en
1o0. Al revés no funciona:1 as boolno compila. Usa una comparación comon != 0.
Convertir texto en números
Sección titulada «Convertir texto en números»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.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.
Convertir números en texto
Sección titulada «Convertir números en texto»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 + "!");}Práctica
Sección titulada «Práctica»1. Nota media
Sección titulada «1. Nota media»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: 25media: 8.332. Un precio en texto
Sección titulada «2. Un precio en texto»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.5Sin as f64, Rust se negaría a multiplicar un f64 por un i32, porque nunca mezcla tipos numéricos por ti.
Resumen
Sección titulada «Resumen»- Rust nunca convierte tipos automáticamente: siempre conviertes de forma explícita.
- Usa
aspara 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).charybooltambién se pueden convertir en números. - Usa
.parse()para convertir texto en número, y.to_string()para lo contrario.
Comprueba lo que aprendiste
Sección titulada «Comprueba lo que aprendiste»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
Para leer más
Sección titulada «Para leer más»- Casting: Rust by Example (en inglés): muchas conversiones con
asque puedes ejecutar, con comentarios sobre lo que produce exactamente cada una. - Type cast expressions: The Rust Reference (en inglés): la tabla completa de qué conversiones están permitidas y la regla precisa de cada una.
- To and from Strings: Rust by Example (en inglés):
.to_string()y.parse()con un poco más de detalle. TryFrom: documentación de la biblioteca estándar (en inglés): la conversión comprobada (u8::try_from(...)) que conviene usar cuando un valor podría no caber.- Numeric Types: The Rust Reference (en inglés): el tamaño y el rango de cada tipo entero y decimal.