In Rust, integers are one of the basic data types, used to represent numbers without fractional parts.

Integer Types and Annotation Methods

Rust's integer types include signed integers (starting with i) and unsigned integers (starting with u), with bit widths of 8, 16, 32, 64, 128 bits, as well as platform-dependent isize and usize. For example, i32 represents a 32-bit signed integer. Type annotation can be done through explicit declaration or using suffixes.

let a: i32 = 42; // Explicit type annotation
let b = 42u8; // Using suffix annotation for u8
let c = 42; // Type inference as i32 (default)

Underscores _ can be used to improve readability without affecting the numerical value:

let million = 1_000_000;      // Equivalent to 1000000
let billion = 1_000_000_000;  // Equivalent to 1000000000
let val = 1_2345_678;   // Equivalent to 12345678

Difference Between Signed and Unsigned

Signed integers can represent positive numbers, negative numbers, and zero, while unsigned integers can only represent non-negative numbers (including zero). For example, the range of i8 is -128 to 127, and the range of u8 is 0 to 255.

let signed: i8 = -50; // Valid
let unsigned: u8 = 200; // Valid
// let invalid: u8 = -10; // Compilation error: cannot assign negative number to unsigned type

Numerical Range

The minimum value for unsigned integers is 0, and the maximum value is 2^n - 1;

The minimum value for signed integers is -2^(n-1), and the maximum value is 2^(n-1) - 1;

Where n is the number of bits;

You can use the standard library's MAX and MIN constants to get the minimum and maximum values of a type:

fn main() {
    // Using MIN and MAX associated constants
    println!("i8: {} to {}", i8::MIN, i8::MAX);
    println!("u8: {} to {}", u8::MIN, u8::MAX);
    println!("i16: {} to {}", i16::MIN, i16::MAX);
    println!("u16: {} to {}", u16::MIN, u16::MAX);
    println!("i32: {} to {}", i32::MIN, i32::MAX);
    println!("u32: {} to {}", u32::MIN, u32::MAX);
    println!("i64: {} to {}", i64::MIN, i64::MAX);
    println!("u64: {} to {}", u64::MIN, u64::MAX);
    println!("i128: {} to {}", i128::MIN, i128::MAX);
    println!("u128: {} to {}", u128::MIN, u128::MAX);
    println!("isize: {} to {}", isize::MIN, isize::MAX);
    println!("usize: {} to {}", usize::MIN, usize::MAX);
}

Basic Numerical Calculation Methods

Rust supports basic arithmetic operations such as addition, subtraction, multiplication, and division. Integer division truncates towards zero, discarding the remainder.

let sum = 10 + 5; // 15
let diff = 10 - 5; // 5
let product = 10 * 5; // 50
let quotient = 10 / 3; // 3 (integer division)
let remainder = 10 % 3; // 1 (remainder)

Type Conversion and Truncation

Rust requires explicit type conversion using the as keyword:

// Upcasting (no loss)
let a: u8 = 42;
let b: u32 = a as u32;     // 42 -> 42
let c: u64 = a as u64;     // 42 -> 42
let d: i128 = a as i128;   // 42 -> 42
    
// Downcasting (may truncate)
let large: u32 = 1000;
let small: u8 = large as u8;
println!("{} -> {}", large, small);  // 1000 -> 232

Numerical truncation refers to discarding bits that exceed the target type's range during type conversion or operations, retaining only the lower bits.

fn main() {
    let x: u16 = 300;      // 16-bit unsigned
    let y: u8 = x as u8;   // Convert to 8-bit unsigned

    // 16-bit binary representation of 300
    // High bits--------Low bits
    //0000000100101100
    // After converting to 8-bit unsigned, only the lower 8 bits are retained
    //00101100 // Binary of 44

    println!("{}",y);   // 44
}

Other Base Representations

Rust allows using different base literals to represent integers, such as binary, octal, and hexadecimal.

let decimal = 42;       // Decimal (default, no prefix)
let binary = 0b101010;  // Binary (0b prefix)
let octal = 0o52;       // Octal (0o prefix, letter o)
let hex = 0x2A;         // Hexadecimal (0x prefix)

// All bases support underscore separation
let with_underscore = 0b1010_1010;