Originally published on php2rust.dev — part of the PHP to Rust course. View this lesson on the original site.

Rust offers many integer types with fixed sizes. PHP has a single int type (usually 64-bit).

Rust integer types

What do the numbers (8, 16, 32, …) mean?

The suffix on each type is the width of the value in bits, how many binary digits Rust uses to store one number of that type in memory.

  • i32 → 32 bits (4 bytes) per value
  • i64 → 64 bits (8 bytes) per value
  • Same idea for i8, i16, i128, and all u* types.

More bits mean a larger range of representable integers (and more memory per variable). The type is fixed: an i16 cannot silently grow to hold a bigger number; if a computation overflows, behaviour depends on build mode (panic in debug, wrap in release unless you use checked APIs, covered later in the course).

i8 vs i16 vs i32 …, what actually changes?

Only width (and therefore range and stack / struct size). i8 through i128 all mean “signed integer”; the language doesn’t give i64 different operators from i8. You pick a type so every value you need fits without overflow and so you don’t waste space or mismatch a foreign API (e.g. a C struct field is int32_t → use i32).

Unsigned types follow the same pattern: u8 vs u16 vs u32 is still “how many bits,” with u meaning “non-negative only.” A u16 is not the same numeric range as i16: both use 16 bits, but one bit pattern is reserved for sign in i16, so max values differ.

Signed (i*) types use one bit for sign; roughly half the patterns are negative, half non-negative:

  • Range for iN: −2^(N−1) through 2^(N−1) − 1 (for example i32: −2^31 … 2^31 − 1)

Unsigned (u*) types store only zero and positive whole numbers; all bits contribute to magnitude:

  • Range for uN: 0 through 2^N − 1

Ranges at a glance

Type Bits Approximate range
i8 8 −128 … 127
i16 16 −32_768 … 32_767
i32 32 −2_147_483_648 … 2_147_483_647
i64 64 about ±9.2 × 10^18
i128 128 enormous (good for cryptography, timestamps, big aggregates)
u8 8 0 … 255
u16 16 0 … 65_535
u32 32 0 … 4_294_967_295
u64 64 0 … about 1.84 × 10^19
u128 128 0 … very large

i32 is the default when you write an integer literal and the compiler infers an integer type, it’s a good balance of range and size on all platforms.

Choosing a width

  • i8 / u8: tiny counts, raw bytes, compact structs, binary protocols (e.g. one byte per channel 0–255).
  • i16 / u16: small IDs, audio samples, legacy file formats.
  • i32 / u32: general arithmetic, loop counters, many APIs (Unix error codes as i32, IPv4 addresses as u32, etc.).
  • i64 / u64: file sizes, timestamps in nanoseconds, anything that can exceed i32’s ~2.1 billion.
  • i128 / u128: when you need even more headroom without switching to a big-int crate yet.

isize and usize

These are pointer-sized: on a 64-bit program they behave like 64-bit integers for width; on 32-bit, like 32-bit. Use them for memory indexing, lengths and indices of slices, vectors, and arrays, so they always match what the platform can address.

fn main() {
    let a: i32 = -42;
    let b: u32 = 42;
    let c: u8 = 255;
    let index: usize = 0;  // Idiomatic for array/slice indices

    // Literal suffixes
    let d = 100i64;
    let e = 1_000_000_u32;  // Underscores for readability

    println!("a={}, b={}, c={}, index={}, d={}, e={}", a, b, c, index, d, e);
}

PHP integers

PHP has one integer type, typically 64-bit signed:

<?php
$a = -42;
$b = 42;
$c = 255;

// PHP 7.4+: underscore in numeric literals
$e = 1_000_000;

echo "a=$a, b=$b, c=$c, e=$e\n";

// Overflow becomes float
$big = PHP_INT_MAX + 1;  // Becomes float on 64-bit
var_dump($big);  // float(9.223372036854776E+18)

PHP does not have unsigned integers or fixed-size types. Overflow converts to float.

Comparison

  • Rust: The number in the type name is the bit width; range follows from that. You choose i8…i128 / u8…u128 explicitly; isize/usize match the address space. Overflow is explicit (panic, wrap, or checked math, not silent growth).
  • PHP: Single int type; the engine picks a width (often 64-bit signed on modern PHP). You don’t declare int8 vs int64. Overflow can become float. No unsigned integers in the type system.

References

What's next

Next: Floating-point numbers.

From PHP to Rust — Rust Syntax and Functions