5.7 Numeric Literals

Each numeric literal in Rust must have a well-defined type at compile time, decided by context or by an explicit suffix.

5.7.1 Integer Literals

By default, integer literals are i32. You can add a type suffix (like 123u16) to specify another type. Underscores (_) are allowed within numeric literals for readability:

#![allow(unused)]
fn main() {
let large = 1_000_000; // 1 million, i32
}

5.7.2 Floating-Point Literals

By default, floating-point literals are f64. To specify f32, you can add a suffix like 3.14f32. Rust requires at least one digit before the decimal point (0.7 is valid, while .7 is not), but you can write a trailing decimal point with no digits after it (1. is equivalent to 1.0).

5.7.3 Hex, Octal, and Binary

Rust supports integer literals in multiple bases: hexadecimal (0x), octal (0o), and binary (0b). Although decimal and hexadecimal are most common, octal can be handy for file permissions in Unix-like systems or certain hardware. You can also create a byte literal with b'X', yielding a u8 for the ASCII code of X.

fn main() {
    let hex = 0xFF;        // 255 in decimal
    let oct = 0o377;       // 255 in decimal
    let bin = 0b1111_1111; // 255 in decimal
    let byte = b'A';       // 65 in decimal (ASCII for 'A')
    println!("{} {} {} {}", hex, oct, bin, byte);
}

5.7.4 Type Inference

Rust infers numeric types by how they are used. For example:

fn main() {
    let array = [10, 20, 30];
    let mut i = 0;        // The literal '0' could be multiple integer types
    while i < array.len() {
        println!("{}", array[i]);
        i += 1;
    }
}

Since i is compared to array.len() (which returns usize) and used to index the array (also requiring usize), the compiler infers i to be usize. Thus, Rust often spares you from writing explicit type annotations. However, if there is not enough information to determine a single valid type, you must provide a hint or cast.