| |

Rust 5 ๐Ÿฆ€ Scalar Data Types: Integers, Floats, Booleans, and Chars

Rust’s type system begins with scalars โ€” types that represent a single value. The language has four primary scalar categories: integers, floating-point numbers, booleans, and characters. These are the atoms from which all larger data structures are built, and understanding their sizes, ranges, and behaviors is essential before working with collections, structs, or enums.

What distinguishes Rust’s scalars from those of other languages is not their existence โ€” every language has numbers and booleans โ€” but the precision with which they are defined. Integer types come in explicit bit widths, floating-point types follow the IEEE-754 standard, booleans occupy exactly one byte, and characters represent full Unicode scalar values rather than ASCII bytes. This precision is a deliberate choice: in systems programming, knowing the exact size and representation of your data is not optional.

This chapter covers the integer family (signed, unsigned, and pointer-sized), the two floating-point types and their trade-offs, the boolean type and its operations, and the character type with its Unicode semantics. We will also examine integer overflow โ€” a behavior that differs between debug and release builds โ€” and the methods Rust provides for handling it explicitly.

Key point: Rust provides explicit, sized scalar types: integers from 8 to 128 bits plus pointer-sized variants, two IEEE-754 floating-point types, a one-byte boolean, and a four-byte Unicode character type.


Why these scalar types exist

The data representation problem. Systems programming requires knowing exactly how many bytes a value occupies and what range it can represent. A C int is 16 bits on some platforms and 32 on others; a long varies even more widely. Rust eliminates this ambiguity by making the bit width part of the type name. i32 is always 32 bits, u8 is always 8 bits, and isize/usize are explicitly pointer-sized. This makes code portable across architectures without relying on platform-specific assumptions .

The signedness problem. Unsigned integers cannot represent negative numbers but double the positive range of their signed counterparts. Some algorithms โ€” bit manipulation, array indexing, hash computation โ€” are naturally unsigned. Others โ€” temperature differences, financial balances, coordinate offsets โ€” are naturally signed. Rust provides both and requires you to choose, making the sign explicit in the type rather than implicit in the programmer’s head .

The floating-point precision problem. Floating-point arithmetic is approximate, but different applications need different trade-offs. f32 is half the size of f64 and faster on some embedded platforms, but it offers only about seven decimal digits of precision. f64 offers roughly sixteen and is the default on modern hardware because the performance difference is negligible for most workloads. Rust exposes both and defaults to f64 for the precision .

The Unicode problem. In C, a char is one byte and represents an ASCII character. Any non-ASCII text must be handled as bytes or wide characters with locale-dependent semantics. Rust’s char is four bytes and represents a Unicode Scalar Value โ€” a single code point from U+0000 to U+10FFFF, excluding surrogate code points. This means accented letters, Greek symbols, Chinese characters, and emoji are all single char values, though the distinction between a “character” and a “Unicode code point” requires care when working with combined graphemes .

The overflow safety problem. Integer overflow โ€” when a value exceeds the range of its type โ€” is undefined behavior in C and a silent wrap in many other languages. Rust makes this a defined, checkable behavior. In debug builds, overflow panics. In release builds, it wraps using two’s complement. And for cases where you need explicit control, Rust provides four method families: wrapping_*, checked_*, overflowing_*, and saturating_* .


a. Integer types and literals

An integer is a number without a fractional component. Rust provides six signed types (i8, i16, i32, i64, i128, isize) and six unsigned types (u8, u16, u32, u64, u128, usize). The number indicates bit width; isize and usize are pointer-sized, meaning 64 bits on a 64-bit architecture and 32 bits on a 32-bit one .

let small: i8 = -128;
let large: u64 = 18_446_744_073_709_551_615;
let index: usize = 42;
let default_int = 5; // inferred as i32

Signed integers range from -(2^(n-1)) to 2^(n-1) - 1. So i8 spans -128 to 127. Unsigned integers range from 0 to 2^n - 1; u8 spans 0 to 255. The i128 and u128 types exist for when you need wider ranges, though they are slower on some platforms because the hardware lacks native 128-bit arithmetic .

Integer literals can be written in several forms, all of which allow underscores as visual separators and type suffixes :

let decimal = 98_222;
let hex = 0xff;
let octal = 0o77;
let binary = 0b1111_0000;
let byte = b'A'; // u8 only

When you do not annotate a type, Rust infers i32 by default. This is generally the fastest integer type, even on 64-bit systems, and its range is sufficient for most calculations . The primary exception is when indexing collections, where you need usize because indices cannot be negative and must match the platform’s pointer width.

b. Floating-point types and operations

Rust has two floating-point types: f32 (single precision, 32 bits) and f64 (double precision, 64 bits). Both follow the IEEE-754 standard, which defines how sign, exponent, and mantissa bits are laid out and how operations like rounding and special values (infinity, NaN) behave .

let single: f32 = 3.14159;
let double = 2.71828; // inferred as f64

The default is f64 because on modern CPUs it is roughly the same speed as f32 but offers significantly more precision โ€” about 15 to 17 significant decimal digits versus 6 to 9 for f32. On 32-bit embedded systems, f32 may be faster because f64 requires software emulation, but for most desktop and server workloads, f64 is the better default .

All floating-point types are signed; there is no unsigned float. Rust supports the standard arithmetic operations: +, -, *, /, and %. Division by zero in floating-point yields infinity or NaN rather than panicking, following IEEE-754 semantics .

let a = 5.0 / 2.0; // 2.5
let b = 5.0 % 2.0; // 1.0
let c = 0.0 / 0.0; // NaN

c. Booleans and characters

The boolean type in Rust is bool, with two possible values: true and false. It occupies exactly one byte . Booleans are the type of all conditional expressions and the result of comparison operators.

let active: bool = true;
let finished = false;
if active && !finished {
    println!("Still running");
}

Boolean values support the bitwise operators & (AND), | (OR), and ^ (XOR), as well as the logical operators && and ||, which short-circuit. A bool can be cast to an integer: true as i32 is 1, and false as i32 is 0 .

The char type represents a single Unicode Scalar Value. It is four bytes in size and is written with single quotes, distinguishing it from string literals which use double quotes .

let letter = 'a';
let greek = 'ฮฑ';
let emoji = '๐Ÿฆ€';
let chinese = 'ไธญ';

Unicode Scalar Values range from U+0000 to U+D7FF and U+E000 to U+10FFFF. The gap between D7FF and E000 contains surrogate code points, which are not valid char values because they are used only in UTF-16 encoding and cannot represent a standalone character .

A crucial caveat: a char is not always the same as a human-perceived “character.” Unicode combines some graphemes from multiple code points โ€” an accented character like “รฉ” can be a single code point (U+00E9) or a base “e” followed by a combining accent (U+0065 U+0301). A char holds one code point, not one grapheme cluster. This distinction becomes important when processing text .


Complete Example Session

// ============================================
// PART 1: INTEGER TYPES
// ============================================
// Signed and unsigned integers with explicit widths.

fn main() {
    let tiny: i8 = -128;
    let small: u8 = 255;
    let medium: i32 = -2_000_000_000;
    let huge: u64 = 18_446_744_073_709_551_615;
    println!("{} {} {} {}", tiny, small, medium, huge);
}
// ============================================
// PART 2: INTEGER LITERALS
// ============================================
// Multiple representations, underscores, suffixes.

fn main() {
    let dec = 1_000_000;
    let hex = 0xdead_beef;
    let oct = 0o755;
    let bin = 0b1010_1010;
    let byte = b'Z';
    println!("{} {} {} {} {}", dec, hex, oct, bin, byte);
}
// ============================================
// PART 3: DEFAULT INTEGER TYPE
// ============================================
// Unannotated integers default to i32.

fn main() {
    let x = 42; // i32
    println!("{}", x);
}
// ============================================
// PART 4: FLOATING-POINT TYPES
// ============================================
// f32 and f64; default is f64.

fn main() {
    let f: f32 = 3.14;
    let d = 2.71828; // f64
    println!("{} {}", f, d);
}
// ============================================
// PART 5: FLOATING-POINT SPECIAL VALUES
// ============================================
// IEEE-754 semantics for division.

fn main() {
    let inf = 1.0 / 0.0;
    let nan = 0.0 / 0.0;
    println!("{} {}", inf, nan);
}
// ============================================
// PART 6: BOOLEAN TYPE
// ============================================
// bool is one byte; true or false.

fn main() {
    let yes: bool = true;
    let no = false;
    let result = yes && !no;
    println!("{}", result);
}
// ============================================
// PART 7: BOOLEAN CASTING
// ============================================
// true as i32 is 1; false as i32 is 0.

fn main() {
    let t = true as i32;
    let f = false as i32;
    println!("{} {}", t, f);
}
// ============================================
// PART 8: CHARACTER TYPE
// ============================================
// char is four bytes, Unicode Scalar Value.

fn main() {
    let a = 'A';
    let omega = 'ฮฉ';
    let crab = '๐Ÿฆ€';
    println!("{} {} {}", a, omega, crab);
}
// ============================================
// PART 9: INTEGER OVERFLOW IN DEBUG
// ============================================
// Overflow panics in debug builds.

fn main() {
    let mut x: u8 = 255;
    // x += 1; // panics: attempt to add with overflow
    println!("{}", x);
}
// ============================================
// PART 10: EXPLICIT OVERFLOW HANDLING
// ============================================
// wrapping_add wraps; checked_add returns Option.

fn main() {
    let x: u8 = 255;
    let wrapped = x.wrapping_add(1); // 0
    let checked = x.checked_add(1);  // None
    println!("{:?} {:?}", wrapped, checked);
}

These ten parts cover the four scalar categories, their literal forms, default inference, special floating-point values, boolean casting, Unicode characters, and overflow behavior. The final example shows the wrapping_* and checked_* method families that give explicit control over edge cases.


Quick Reference

Integer Types

TypeSizeRange (Signed)Range (Unsigned)
i8 / u88-bit-128 to 1270 to 255
i16 / u1616-bit-32,768 to 32,7670 to 65,535
i32 / u3232-bit-2,147,483,648 to 2,147,483,6470 to 4,294,967,295
i64 / u6464-bit-9.2e18 to 9.2e180 to 1.8e19
i128 / u128128-bit-1.7e38 to 1.7e380 to 3.4e38
isize / usizepointerplatform-dependentplatform-dependent

Floating-Point Types

TypeSizePrecisionDefault
f3232-bit~7 decimal digitsNo
f6464-bit~16 decimal digitsYes

Scalar Type Sizes

TypeSize
Integer8โ€“128 bits
Float32 or 64 bits
bool1 byte
char4 bytes

Overflow Methods

MethodBehavior on Overflow
wrapping_addWraps to minimum/maximum
checked_addReturns None
overflowing_addReturns (value, bool)
saturating_addClamps to min/max

Best Practices

โœ… Do This:

let x: i32 = 42;                                    // Explicit when clarity matters
let index: usize = 0;                               // Use usize for indexing
let f = 3.14;                                       // Default f64 for precision
let b: bool = true;                                 // bool for conditionals
let c = '๐Ÿฆ€';                                        // char for Unicode
let result = a.checked_add(b);                      // Explicit overflow handling
let hex = 0xFF;                                     // Hex for bit patterns

โŒ Don’t Do This:

let x = 42;                                         // โŒ Ambiguous when type matters
let index: i32 = 0;                                 // โŒ i32 for indexing
let f: f32 = 3.14;                                  // โŒ f32 when f64 works
let c = "a";                                        // โŒ String, not char
let x: u8 = 255; x += 1;                            // โŒ Panics in debug
let val = a.wrapping_add(b);                        // โŒ Silent wrap when unexpected

Common Pitfalls

PitfallWhy It HappensFix
Overflow panic in debugAdding 1 to max valueUse wrapping_add, checked_add, or wider type
Silent wrap in releaseSame operation, different build modeUse explicit overflow methods
usize/i32 mismatchIndex requires usizeCast with as usize or annotate
char from multiple code pointsGrapheme is not a code pointUse string slice for graphemes
Float comparison failsNaN never equals anythingUse is_nan() or epsilon comparison
Precision loss with f327 digits insufficientUse f64 for calculations
b'A' as u8 onlyByte literal type restrictionUse b'A' as char or 'A'

Real-World Examples

1. Configuration Constant

const MAX_CONNECTIONS: u32 = 1024;
const TIMEOUT_MS: u64 = 30_000;

2. Array Index

let data = [10, 20, 30];
let i: usize = 1;
let value = data[i];

3. Financial Calculation

let price: f64 = 19.99;
let tax_rate = 0.08;
let total = price * (1.0 + tax_rate);

4. Temperature Conversion

fn c_to_f(c: f64) -> f64 {
    c * 9.0 / 5.0 + 32.0
}

5. Boolean Flag

let is_valid = input.len() > 0 && input.starts_with('a');

6. Character Classification

let c = '7';
if c.is_ascii_digit() {
    println!("digit");
}

7. Bitmask

let flags: u8 = 0b1010_0101;
let mask = 0b0000_1111;
let low = flags & mask;

8. Safe Addition

match a.checked_add(b) {
    Some(sum) => println!("{}", sum),
    None => println!("overflow"),
}

9. Saturating Counter

let mut count: u8 = 250;
count = count.saturating_add(10); // 255, not wrap

10. Unicode Iteration

for c in "hรฉllo".chars() {
    println!("{}", c);
}

Visual

Integer Types and Ranges

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  SIGNED vs UNSIGNED INTEGER RANGES                           โ”‚
โ”‚                                                              โ”‚
โ”‚  i8:   -128 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 127                     โ”‚
โ”‚  u8:      0 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 255                     โ”‚
โ”‚                                                              โ”‚
โ”‚  i16:  -32768 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 32767                   โ”‚
โ”‚  u16:     0 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 65535                   โ”‚
โ”‚                                                              โ”‚
โ”‚  i32:  -2.1B โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 2.1B                    โ”‚
โ”‚  u32:     0 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 4.2B                    โ”‚
โ”‚                                                              โ”‚
โ”‚  isize/usize: pointer-sized (64-bit on 64-bit platforms)     โ”‚
โ”‚                                                              โ”‚
โ”‚  Signed: can go negative, half range in each direction       โ”‚
โ”‚  Unsigned: non-negative only, full range positive            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Float Precision

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  f32 vs f64 PRECISION                                        โ”‚
โ”‚                                                              โ”‚
โ”‚  f32 (single precision):                                     โ”‚
โ”‚  โ”œโ”€โ”€ 32 bits total                                           โ”‚
โ”‚  โ”œโ”€โ”€ 1 sign + 8 exponent + 23 mantissa                       โ”‚
โ”‚  โ””โ”€โ”€ ~7 decimal digits of precision                          โ”‚
โ”‚                                                              โ”‚
โ”‚  f64 (double precision):                                     โ”‚
โ”‚  โ”œโ”€โ”€ 64 bits total                                           โ”‚
โ”‚  โ”œโ”€โ”€ 1 sign + 11 exponent + 52 mantissa                      โ”‚
โ”‚  โ””โ”€โ”€ ~16 decimal digits of precision                         โ”‚
โ”‚                                                              โ”‚
โ”‚  Default: f64 (same speed on modern CPUs, more precision)    โ”‚
โ”‚  Use f32 only on memory-constrained embedded systems         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Integer Overflow Behavior

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  OVERFLOW: DEBUG vs RELEASE                                  โ”‚
โ”‚                                                              โ”‚
โ”‚  let x: u8 = 255;                                            โ”‚
โ”‚  x + 1                                                       โ”‚
โ”‚                                                              โ”‚
โ”‚  DEBUG BUILD:                                                โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  panic: attempt to add with overflow                   โ”‚  โ”‚
โ”‚  โ”‚  Program crashes immediately.                          โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  RELEASE BUILD:                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  Result: 0 (wraps around)                              โ”‚  โ”‚
โ”‚  โ”‚  No panic; silent two's complement wrapping.           โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  EXPLICIT METHODS (same in both builds):                     โ”‚
โ”‚  โ”œโ”€โ”€ wrapping_add โ†’ 0                                        โ”‚
โ”‚  โ”œโ”€โ”€ checked_add โ†’ None                                      โ”‚
โ”‚  โ”œโ”€โ”€ overflowing_add โ†’ (0, true)                             โ”‚
โ”‚  โ””โ”€โ”€ saturating_add โ†’ 255                                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Unicode Scalar Value Range

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  char: UNICODE SCALAR VALUES (4 bytes)                       โ”‚
โ”‚                                                              โ”‚
โ”‚  U+0000 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ U+D7FF  โœ… valid char   โ”‚
โ”‚                                                              โ”‚
โ”‚  U+D800 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ U+DFFF  โŒ surrogates   โ”‚
โ”‚                                                              โ”‚
โ”‚  U+E000 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ U+10FFFF  โœ… valid char โ”‚
โ”‚                                                              โ”‚
โ”‚  Examples:                                                   โ”‚
โ”‚  'a' = U+0061                                                โ”‚
โ”‚  'ฮฑ' = U+03B1                                                โ”‚
โ”‚  'ไธญ' = U+4E2D                                               โ”‚
โ”‚  '๐Ÿฆ€' = U+1F980                                              โ”‚
โ”‚                                                              โ”‚
โ”‚  A char is one code point, not one grapheme.                 โ”‚
โ”‚  "รฉ" can be U+00E9 or U+0065 U+0301 (e + combining accent).  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Integer typesi8โ€“i128, u8โ€“u128, isize, usize
Default integeri32
Float typesf32 (single), f64 (double)
Default floatf64
Boolean typebool, 1 byte, values true/false
Character typechar, 4 bytes, Unicode Scalar Value
Integer literalsDecimal, hex (0x), octal (0o), binary (0b), byte (b'A')
Overflow (debug)Panics
Overflow (release)Wraps (two’s complement)
Explicit overflowwrapping_*, checked_*, overflowing_*, saturating_*
char rangeU+0000โ€“U+D7FF, U+E000โ€“U+10FFFF

Key takeaways:

  • Integer types are explicitly sized. i32 is always 32 bits, u8 always 8, and isize/usize match the pointer width of the target platform .
  • Signed and unsigned have different ranges. Signed integers use two’s complement and span negative to positive; unsigned start at zero .
  • f64 is the default float. It offers roughly 16 decimal digits of precision at essentially the same speed as f32 on modern hardware .
  • bool is one byte and casts to 0 or 1. It is the result type of comparisons and the condition type for if expressions .
  • char is four bytes and Unicode-aware. It represents a Unicode Scalar Value, not a byte or a grapheme cluster .
  • Overflow behavior differs by build mode. Debug panics; release wraps silently. Use explicit methods for predictable behavior .
  • usize is required for indexing. Collection indices cannot be negative and must match the platform’s pointer size .
  • Integer literals support underscores and suffixes. 1_000_000u64 is valid and readable .

Remember: Rust’s scalar types are the foundation of every value your programs manipulate. The integer types provide explicit widths and signedness, eliminating platform-dependent ambiguity. The two float types trade precision against size, with f64 as the sensible default. Booleans are one byte and drive all conditional logic. Characters are four bytes and Unicode-aware, capable of representing every symbol from every writing system. The overflow rules โ€” panic in debug, wrap in release โ€” and the explicit method families for controlling overflow give you the tools to handle edge cases deliberately. When you choose a scalar type, you are choosing a contract: how much memory it uses, what values it can hold, and how it behaves at its limits.



Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!