Rust divide los números enteros en dos categorías principales: los tipos con signo (i de integer) y los tipos sin signo (u de unsigned). Los tipos con signo, como i8, i32 o i128, pueden representar valores negativos, cero y positivos. Los tipos sin signo, como u8 o u64, solo pueden representar valores positivos o cero. El número que acompaña al prefijo indica la cantidad de bits que ocupa el tipo en memoria; a mayor número de bits, mayor es el rango de valores que puede almacenar, pero también mayor es el espacio que ocupa.

Existen también los tipos isize e usize, cuyos tamaños dependen de la arquitectura del procesador (32 o 64 bits). El tipo usize es fundamental porque se utiliza para representar el tamaño de objetos en memoria y para indexar colecciones (como vectores), ya que su tamaño siempre coincide con la capacidad máxima de direccionamiento del sistema.

Para escribir números enteros (literales), Rust ofrece varias formas. Se pueden usar guiones bajos para facilitar la lectura de números grandes (ej. 1_000_000), o prefijos para diferentes bases: 0b para binario, 0o para octal y 0x para hexadecimal. También es posible indicar el tipo directamente con un sufijo, como 57u8.

Un error común es el desbordamiento (overflow), que ocurre cuando un cálculo supera el límite permitido por el tipo (por ejemplo, sumar 1 a un u8 que ya vale 255). En modo de depuración (debug), Rust detectará esto y detendrá el programa con un panic. En modo de optimización (release), el programa continuará con un “desbordamiento silencioso” (wrapping), lo que puede causar errores lógicos graves. Para manejar esto de forma segura, Rust proporciona métodos específicos: checked_add (devuelve un Option si hay error), saturating_add (se queda en el valor máximo/mínimo) y wrapping_add (realiza el desbordamiento de forma controlada). Finalmente, el uso de as permite convertir un tipo en otro (casting), pero debe usarse con cautela, ya que puede truncar información si el destino es más pequeño que el origen.

fn main() {
    // Literales con diferentes formatos y sufijos
    let valor_u8: u8 = 0b1111_0000; // Binario con separador de guion
    let valor_hex: u8 = 0xFF;      // Hexadecimal
    let valor_grande: i32 = 1_000_000; // Entero con guion para legibilidad

    // Tipos dependientes de la arquitectura
    let indice: usize = 10; // Usado para indexación
    let entero_arquitectura: isize = -5;

    // Conversión de tipos (casting) con el operador 'as'
    let numero_i32: i32 = 100;
    let numero_u8_truncado = numero_i32 as u8; 

    // Gestión segura de desbordamiento (overflow)
    let max_u8: u8 = 255;

    // 1. checked_add: Devuelve None si ocurre overflow
    let resultado_checked = max_u8.checked_add(1);

    // 2. saturating_add: Se queda en el límite (255)
    let resultado_saturating = max_u8.saturating_add(1);

    // 3. wrapping_add: Da la vuelta al ciclo (vuelve a 0)
    let resultado_wrapping = max_u8.wrapping_add(1);

    println!("Binario: {:08b}, Hex: {:X}, Grande: {}", valor_u8, valor_hex, valor_grande);
    println!("Indice: {}, Truncado: {}", indice, numero_u8_truncado);
    println!("Checked: {:?}, Saturating: {}, Wrapping: {}", 
             resultado_checked, resultado_saturating, resultado_wrapping);
}

Explicación del Código

  • valor_u8: Es un u8 definido mediante un literal binario (0b) con guiones bajos para separar bits.
  • valor_hex: Es un u8 definido mediante un literal hexadecimal (0x).
  • valor_grande: Es un i32 que utiliza guiones bajos (1_000_000) para mejorar la legibilidad visual.
  • indice: Es de tipo usize, el tipo estándar para representar tamaños y posiciones en memoria.
  • entero_arquitectura: Es de tipo isize, cuyo tamaño varía según el procesador.
  • numero_i32: Un entero de 32 bits que se usará para la conversión.
  • numero_u8_truncado: Resultado de usar as para convertir un i32 a u8.
  • max_u8: Un u8 con el valor máximo posible (255), usado para demostrar desbordamientos.
  • resultado_checked: Utiliza checked_add(1). Como 255 + 1 desborda, devuelve None.
  • resultado_saturating: Utiliza saturating_add(1). Al desbordar, el valor se mantiene en 255.
  • resultado_wrapping: Utiliza wrapping_add(1). Al desbordar, el valor “da la vuelta” y se convierte en 0.

13