Thuta Learning
Rust
BasicProgrammingbeginner

Data Types — Scalar and Compound

What you'll walk away with

  • Explain the core ideas behind Data Types — Scalar and Compound
  • Run the sample Rust code and verify its output
  • Apply the technique correctly to the Tutorial Platform and production scenarios

Build the mental model

Rust is statically typed, so every variable's type must be known at compile time — the compiler can often infer it from context (`let x = 5;` defaults to `i32`), but ambiguous contexts need an explicit annotation like `let x: u32 = 5;`. There are four scalar types: integers (`i8` through `i128` signed, `u8` through `u128` unsigned, each with a precisely fixed bit width), floating-point numbers (`f32`, `f64`), booleans (`bool`), and characters (`char`, a 4-byte Unicode scalar value). There are two compound types: tuples (fixed-length groups that can mix types, like `(i32, f64, char)`) and arrays (fixed-length, same-type elements, like `[i32; 5]`). What all of these types share is that their exact size is known at compile time, so by default they're stored directly on the stack — no heap allocation or pointer indirection needed, which makes access fast. This contrasts with dynamically-sized data like `String` and `Vec<T>`, which live on the heap — a contrast you'll meet again when `String` shows up in Lesson 8.

Connect it to a real scenario

In the content analyzer tool, return each file's statistics as a `(String, u32, f64)` tuple — file name, word count, and average word length carried together as one group. To track how many lessons exist per difficulty level, a `[u32; 3]` array (indexed for Basic, Intermediate, Advanced) works well, and knowing its size at compile time keeps bounds-checking efficient at runtime. Declare word count fields as `u32` (unsigned, since negative counts are never valid) rather than `i32` — `i32` would fail to enforce at the type level that a negative count is conceptually impossible.

Try the working example

rust
fn main() {
    let stats: (String, u32, f64) = (String::from("ownership.md"), 842, 5.3);
    let (name, word_count, avg_len) = stats;
    println!("{name}: {word_count} words, avg length {avg_len}");

    let lessons_per_level: [u32; 3] = [7, 7, 6];
    println!("Basic lessons: {}", lessons_per_level[0]);
}
You should see
You print "ownership.md: 842 words, avg length 5.3" and "Basic lessons: 7".

5-minute try-it

Create a `(String, u32)` tuple and a `[u32; 5]` array — destructure the tuple's two values and print three of the array's elements by index.

One important caution

Blanket-using the default integer type (`i32`) for count/length fields that can logically never be negative — `u32` would enforce that constraint at the type level, but habit often leads to `i32` everywhere.

Trying to access an array index beyond its compile-time size (like index 3 on a `[u32; 3]`) — Rust catches this with a runtime panic, but it's still a logic error the compiler cannot catch ahead of time.

The Rust Programming Language — Data TypesRust

Easy traps

  • Blanket-using the default integer type (`i32`) for count/length fields that can logically never be negative — `u32` would enforce that constraint at the type level, but habit often leads to `i32` everywhere.
  • Trying to access an array index beyond its compile-time size (like index 3 on a `[u32; 3]`) — Rust catches this with a runtime panic, but it's still a logic error the compiler cannot catch ahead of time.
  • Validate sample code in a local or test environment before applying it to a production system.

Exercise

Create a `(String, u32)` tuple and a `[u32; 5]` array — destructure the tuple's two values and print three of the array's elements by index.

You'll know it worked when: You print "ownership.md: 842 words, avg length 5.3" and "Basic lessons: 7".

Data Types — Scalar and Compound | Thuta Learning