Rust Type Annotations
A type annotation is a type written after a variable name. Rust usually guesses types without an annotation.
State the type after a colon
An annotation writes the type in words, after the name:
let score: u32 = 90;
println!("score = {score}");Pin the type to the number itself
A suffix does the same job without a colon. 5i32 is an i32. 0.5f32 is an f32. 7u8 is a u8:
let a = 5i32;
let b = 0.5f32;
let c = 7u8;
println!("{} {} {}", a, b, c);No clue? Rust picks a default
A plain whole number becomes an i32, and a plain decimal becomes an f64:
let n = 7;
let d = 3.0;
println!("{} {}", n, d);Measure a value
size_of_val counts the bytes a value takes. Watch the defaults appear: the plain whole number takes 4 bytes, the plain decimal 8:
use std::mem::size_of_val;
println!("u8 = {} bytes", size_of_val(&1u8));
println!("u32 = {} bytes", size_of_val(&2u32));
println!("plain whole = {} bytes", size_of_val(&7));
println!("plain decimal = {} bytes", size_of_val(&3.0));A later line can decide the type
Rust looks at later lines too. The big i64 assigned below only fits an i64 — so total was an i64 all along:
let mut total = 12;
total = 4294967296i64;
println!("total = {total}");A variable never changes type
mut allows new values, never a new type. This code fails with error E0308. Use shadowing when you need a new variable with a new type. Shadowing means declaring a fresh variable with the same name:
let mut total = 12;
total = true;Example
fn main() {
let score: u32 = 90;
let ratio = 0.5f32;
let mut total = 12;
println!("starting total = {total}");
total = 4294967296i64;
let default_num = 7;
let default_dec = 3.0;
println!("score = {score} ratio = {ratio}");
println!("total = {total}");
println!("defaults = {default_num} {default_dec}");
}Key points
- The unit type () has exactly one value, also written (): the empty tuple.
- It counts as a simple type, not a compound one, because it holds nothing
In this example, each variable gets its type a different way. score uses an annotation: u32 written after a colon. ratio uses a suffix: 0.5f32 is an f32. total starts as plain 12, which would fit an i32. But a later line assigns 4294967296i64. That number is far too big for i32. So Rust infers that total was i64 from the very start. The last two variables have no clues at all, so the defaults apply. 7 is an i32. 3.0 is an f64, which prints as plain 3.
Note
When Rust truly has no clue, no default saves you: you must write the annotation yourself.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
In let mut total = 12; total = 4294967296i64;, what type is total?