Skip to content

Beginner · Types, control flow and functions · topic 5 of 50 · 25 min

Scalar types: numbers, bool and char

Explanation

A scalar type holds one value. Rust has signed integers (i8 to i128), unsigned integers (u8 to u128), isize and usize, floating-point numbers (f32, f64), bool and char. Integers default to i32 and decimals to f64. Integer overflow panics in a debug build, so Rust gives you checked, wrapping and saturating methods.

Why so many number types?

Rust is a systems language, so it lets you choose exactly how much memory each number uses. A type is the kind of a value; it decides what the value can hold and what you can do with it. Rust is statically typed: every value's type is known when the program is compiled, so many mistakes are caught early.

Integers

SizeSigned (can be negative)Unsigned (0 and up)
8 bitsi8: -128 to 127u8: 0 to 255
16 bitsi16u16: 0 to 65,535
32 bitsi32 (the default)u32: 0 to about 4.29 billion
64 bitsi64u64
128 bitsi128u128
pointer sizeisizeusize: used for indexes and lengths

A bit is a single 0 or 1. More bits hold bigger numbers. Signed types use one bit for the sign. usize matches your computer: 64 bits on a 64-bit machine. Rust uses usize for list positions and lengths, so you will see it often.

rust
let population: u64 = 1_400_000_000;
let temperature: i8 = -5;
let byte: u8 = b'A';     // 65
let mask = 0xff;          // hexadecimal, i32 by default
println!("{population} {temperature} {byte} {mask}");
Prints: 1400000000 -5 65 255. Underscores make big numbers readable and are ignored.

Integer overflow

Overflow means a result is too big (or too small) for its type, like 255 + 1 in a u8. In a debug build, Rust stops the program with a panic, an immediate crash with a message. In a release build, it wraps around silently (255 + 1 becomes 0), unless you turn overflow checks on. Neither is what you want for money or counters, so use the explicit methods:

rust
let a: u8 = 250;
println!("{:?}", a.checked_add(10));    // None: would overflow
println!("{}", a.wrapping_add(10));     // 4: wraps around
println!("{}", a.saturating_add(10));   // 255: stops at the maximum
checked_ returns an Option (Some or None, see module 5); wrapping_ wraps; saturating_ sticks at the limit.

Floating-point numbers

f64 (the default) and f32 hold decimals. They are approximate, like most languages: 0.1 + 0.2 prints 0.30000000000000004. For money, store whole paise in an integer (Rs 12.50 as 1250) instead of a float.

Booleans and characters

bool is true or false. char is one Unicode character in single quotes, and it always takes 4 bytes, so it can hold any letter of any script or an emoji: 'a', '₹', 'क'. Text in double quotes is a string, not a char; strings come in module 4.

Converting with as

rust
let price = 99.99_f64;
let whole = price as i32;      // 99: the decimal part is cut off
let big: i32 = 300;
let small = big as u8;         // 44: 300 does not fit, so it is truncated
println!("{whole} {small}");
as converts between number types but can silently lose data. Prints: 99 44.
Tip: Rust never converts number types automatically. let total: i64 = x + y; where x is i32 is an error. Convert on purpose: i64::from(x), which only exists when no data can be lost, or x as i64.

Common mistakes

  • Mixing types: an i32 plus a u8 does not compile. Convert one side first.
  • Using f64 for money. Use integers of the smallest unit (paise).
  • Using as to shrink numbers without checking. Prefer u8::try_from(x), which returns an error if it does not fit.
  • Assuming overflow is handled the same in debug and release builds. Use checked_ or saturating_ when it matters.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Scalar types: numbers, bool and char · 1/7

Integers Floats bool char

Every value in Rust has a type. Today: the scalar types, which hold a single value.

Prefer a video by a teacher? Find free videos on “rust data types integers floats char bool overflow” on YouTube ↗

In real life: Storing a wallet balance in paise

A wallet app stores every balance as a whole number of paise in a u64 (Rs 1,234.50 is 123450). Adding cashback uses checked_add, so a bug can never wrap a huge balance around to a tiny one; instead the code gets None and reports an error. Prices are only turned into rupees with two decimals when shown to the user.

rust
fn main() {
    let balance_paise: u64 = 123_450;
    let cashback: u64 = 2_500;
    match balance_paise.checked_add(cashback) {
        Some(total) => println!("Rs {}.{:02}", total / 100, total % 100),
        None => println!("overflow!"),
    }
}
Prints: Rs 1259.50. {:02} pads with a zero to two digits.

Practice (0/3 done)

Task 1 · Question

What is the default type of let n = 42; ?

Task 2 · Question

What does this print? let a: u8 = 200; println!("{}", a.saturating_add(100));

Task 3 · Practice

In the Rust Playground or a cargo project, print the result of 0.1 + 0.2, of 255u8.wrapping_add(1), of 255u8.checked_add(1) with {:?}, and of 3.99 as i32. Write one line explaining each result.

Quick quiz

Question 1

1.Which type can hold -20?

Question 2

2.What happens on integer overflow in a debug build?

Question 3

3.How many bytes does a Rust char use?

Question 4

4.What is 7.9_f64 as u8?

Question 5

5.Why store money as paise in an integer?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which type can hold -20?

Answer: i16

Only signed types (starting with i) can be negative.

What happens on integer overflow in a debug build?

Answer: The program panics

Debug builds check for overflow at run time and panic.

How many bytes does a Rust char use?

Answer: 4

A char is a Unicode scalar value stored in 4 bytes.

What is 7.9_f64 as u8?

Answer: 7

as cuts off the decimal part; it does not round.

Why store money as paise in an integer?

Answer: Floats are approximate, integers are exact

Floating-point numbers cannot hold most decimals exactly, which causes rounding errors in money.

Which type should store the population of India (about 1.4 billion) multiplied by 10?Related

Answer: long long

14 billion is beyond the int range (about 2.1 billion), so use long long.

From Variables, types and constants

In char a = 100, b = 100; int c = a + b; what is c?Related

Answer: 200

Promotion to int prevents overflow in the addition.

From Type conversion and casting

Is (i32, f64, bool) Copy?Related

Answer: Yes, because every part is Copy

A tuple is Copy when all of its parts are Copy.

From Copy and Clone

Which type holds true or false?Related

Answer: bool

bool has exactly two values: true and false.

From Types and variables

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 4 more topics in “Types, control flow and functions” before its exam: Compound types: tuples and arrays, Functions, statements and expressions, Control flow: if, loop, while and for, Mini project: reading input from the user.
  2. Module 2 exam: Types, control flow and functions · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Ownership: Rust's big idea. 50 topics left in the course before the final exam.

← Previous: Variables, mutability, shadowing and constants