tipos programacion numericos informatica datos conversion casting rust numbers

casting - programacion - ¿Cómo convierto entre tipos numéricos de forma segura e idiomática?



tipos de datos en pascal (1)

Nota del editor: esta pregunta es de una versión de Rust anterior a 1.0 y hace referencia a algunos elementos que no están presentes en Rust 1.0. Las respuestas aún contienen información valiosa.

¿Cuál es la forma idiomática de convertir (por ejemplo) un usize a un u32 ?

Por ejemplo, la conversión usando 4294967295us as u32 funciona y los documentos de referencia de Rust 0.12 sobre el tipo de conversión dicen

Un valor numérico se puede convertir a cualquier tipo numérico. Un valor de puntero sin formato se puede convertir ao desde cualquier tipo integral o tipo de puntero sin formato. Cualquier otro elenco no es compatible y no se compilará.

pero 4294967296us as u32 se desbordará silenciosamente y dará un resultado de 0.

Encontré ToPrimitive y FromPrimitive que proporcionan buenas funciones como to_u32() -> Option<u32> , pero están marcadas como inestables:

#[unstable(feature = "core", reason = "trait is likely to be removed")]

¿Cuál es la forma idiomática (y segura) de convertir entre tipos numéricos (y punteros)?

El tamaño dependiente de la isize de isize / usize es una de las razones por las que hago esta pregunta: el escenario original era que quería convertir de u32 a usize para poder representar un árbol en un Vec<u32> (por ejemplo, let t = Vec![0u32, 0u32, 1u32] , entonces obtener el abuelo del nodo 2 sería t[t[2us] as usize] ), y me preguntaba cómo fallaría si usize fuera menos de 32 bits.


En ToPrimitive / FromPrimitive

RFC 369, Num Reform, establece :

Idealmente, [...] ToPrimitive [...] se eliminaría en favor de una forma más basada en principios de trabajar con enumeraciones tipo C

Mientras tanto, estos rasgos viven en la caja numérica :

Tratar sin los rasgos

De un tipo que encaja completamente dentro de otro

No hay problema aquí. Utilice From para ser explícito de que no se producen pérdidas:

fn example(v: i8) -> i32 { i32::from(v) // or v.into() }

Puede elegir usar as , pero se recomienda evitarlo cuando no lo necesite (ver más abajo):

fn example(v: i8) -> i32 { v as i32 }

De un tipo que no cabe completamente en otro

No existe un método único que tenga sentido general: está preguntando cómo encajar dos cosas en un espacio destinado a una. Un buen intento inicial es usar una Option : Some cuando el valor se ajusta y None contrario. Luego puede fallar su programa o sustituir un valor predeterminado, según sus necesidades.

Desde Rust 1.34, puede usar TryFrom :

use std::convert::TryFrom; fn example(v: i32) -> Option<i8> { i8::try_from(v).ok() }

Antes de eso, tendría que escribir un código similar usted mismo:

fn example(v: i32) -> Option<i8> { if v > std::i8::MAX as i32 { None } else { Some(v as i8) } }

Que as

pero 4294967296us as u32 se desbordará silenciosamente y dará un resultado de 0

Al convertir a un tipo más pequeño, as solo toma los bits más bajos del número, sin tener en cuenta los bits superiores, incluido el signo:

fn main() { let a: u16 = 0x1234; let b: u8 = a as u8; println!("0x{:04x}, 0x{:02x}", a, b); // 0x1234, 0x34 let a: i16 = -257; let b: u8 = a as u8; println!("0x{:02x}, 0x{:02x}", a, b); // 0xfeff, 0xff }