Types

Primitive Types

Integer Types

TypeSizeRange
i88-bit-128 to 127
i1616-bit-32,768 to 32,767
i3232-bit-2^31 to 2^31-1
i6464-bit-2^63 to 2^63-1
isizepointer-sizedPlatform dependent
u88-bit0 to 255
u1616-bit0 to 65,535
u3232-bit0 to 2^32-1
u6464-bit0 to 2^64-1
usizepointer-sizedPlatform dependent

Integer literals default to i32. Use suffixes for other types: 42u8, 100i64, 0usize.

Floating-Point Types

TypeSizePrecision
f1616-bit~3 decimal digits (IEEE 754 half-precision)
bf1616-bit~3 decimal digits (Brain Float, ML workloads)
f3232-bit~7 decimal digits
f6464-bit~15 decimal digits

Float literals default to f64. Use suffix for f32: 3.14f32.

f16 and bf16 are half-precision types for ML inference and signal processing. bf16 has the same exponent range as f32 but fewer mantissa bits — ideal for neural network weights. Energy cost: 0.4 pJ per operation (vs 0.35 pJ for f32).

Boolean

let a: bool = true;
let b: bool = false;

Character

let c: char = 'A';     // Unicode scalar value
let emoji: char = '\u{1F600}';

Unit Type

The unit type () represents the absence of a meaningful value. Functions without a return type return ().

Compound Types

Tuples

Fixed-length, heterogeneous sequences:

let pair: (i32, String) = (42, "hello");
let (x, y) = pair;     // destructuring
let first = pair.0;     // field access

Arrays

Fixed-length, homogeneous sequences:

let arr: [i32; 5] = [1, 2, 3, 4, 5];
let zeros = [0; 10];    // 10 zeros
let first = arr[0];     // indexing

Slices

Dynamically-sized views into arrays:

let slice: &[i32] = &arr[1..3];

String Types

String

Owned, heap-allocated, growable UTF-8 string:

let s: String = "Hello, world!";
let greeting = "Hi " + name;   // concatenation
let len = s.len();              // byte length

&str

Borrowed string slice:

let s: &str = "literal";

Union Types

Union types allow a value to be one of several types. They are declared with the | separator:

type Number = i32 | i64 | f64;
type JsonValue = i64 | f64 | String | bool | Vec<JsonValue>;
type Result = Data | ErrorCode;

Union types are matched exhaustively:

fn describe(val: Number) -> String {
    match val {
        x: i32 => format!("i32: {}", x),
        x: i64 => format!("i64: {}", x),
        x: f64 => format!("f64: {}", x),
    }
}

Union Type Rules

  • Each constituent type must be distinct
  • The compiler tracks which variant is active at runtime via a discriminant tag
  • Pattern matching on union types is exhaustive -- all variants must be handled
  • Union types compose: type A = B | C where B and C can themselves be union types

Generic Types

Vec

Dynamic array:

let mut v: Vec<i32> = Vec::new();
v.push(1);
v.push(2);
let first = v[0];

Option

Optional value:

let some: Option<i32> = Option::Some(42);
let none: Option<i32> = Option::None;

Result<T, E>

Fallible operation:

let ok: Result<i32, String> = Result::Ok(42);
let err: Result<i32, String> = Result::Err("failed");

Box

Heap-allocated value:

let boxed: Box<i32> = Box::new(42);

HashMap<K, V>

Key-value map:

let mut map: HashMap<String, i32> = HashMap::new();
map.insert("key", 42);

Smart Pointers

See Smart Pointers for full documentation.

let rc = Rc::new(42);            // single-threaded shared ownership
let arc = Arc::new(42);          // thread-safe shared ownership
let cow = Cow::borrowed("hi");   // clone-on-write

Const-Generic Types

// SmallVec — inline buffer with heap spillover
let mut sv: SmallVec[i32; 8] = SmallVec::new();
sv.push(42);   // stored inline (no allocation until > 8 elements)

// Simd — portable SIMD vectors
let v: Simd[f32; 4] = Simd::splat(1.0);
let w: Simd[f32; 4] = Simd::from_array([1.0, 2.0, 3.0, 4.0]);
let sum = v.add(&w);

See Simd for full SIMD documentation.

N-Dimensional Arrays

See NDArray for full documentation.

let mat: NDArray[f64; 2] = NDArray::zeros([3, 4]);
let view: NDView[f64; 1] = mat.row(0);

Type Aliases

pub type Token = Spanned<TokenKind>;
pub type ParseResult<T> = Result<T, ParseError>;

Type Inference

The compiler infers types when possible:

let x = 42;           // inferred as i32
let v = Vec::new();   // type inferred from usage
v.push(1u8);          // now inferred as Vec<u8>

Explicit annotations are required when the type cannot be inferred from context.

Type Casting

Use as for numeric conversions:

let x: i32 = 42;
let y: f64 = x as f64;
let z: u8 = x as u8;    // truncation
let p: usize = x as usize;