Type inference
- Rust course
- Expert
- Lesson 5/46
- 4 min
Learn the Hindley-Milner style type inference algorithm.
Type inference
Rust's type inference works within a function body by collecting constraints and unification: each expression of unknown type gets a type variable, uses create equality constraints between these variables, and the solver solves them all together. That's why information can come "later":
let a = 5; // a: ?T (integer)
let b: u16 = a; // constraint: ?T = u16 → a: u16
let mut v = Vec::new(); // Vec<?U>
v.push('ç'); // ?U = charInference doesn't cross function boundaries: signatures are always written explicitly. This keeps error messages local and APIs stable.
Observing inference
Practical ways to see the inferred type: IDE hints (rust-analyzer), making a deliberate type error (let () = x; makes the compiler state the type), or looking at the size:
let a = 5;
let _b: u16 = a;
println!("{}", std::mem::size_of_val(&a)); // 2: a was inferred as u16
let mut v = Vec::new();
v.push('ç');
println!("{}", std::mem::size_of_val(&v[0])); // 4: charPractice Information that comes later
Declare let a = 5; and assign it to a variable of type u16. Push 'ç' into an empty Vec::new(). Print the results of size_of_val(&a) and size_of_val(&v[0]) separated by a space.
Starter code
fn main() {
// buraya yaz
}Sample solution
fn main() {
let a = 5;
let _b: u16 = a;
let mut v = Vec::new();
v.push('ç');
println!("{} {}", std::mem::size_of_val(&a), std::mem::size_of_val(&v[0]));
}Expected output
2 4
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 With no constraints, what type does <code>let x = 5;</code> get?
- i32 (the integer default) Correct answer
- i64
- usize
- Compile error
Explanation: The default is i32 for integer literals and f64 for floats; it applies only when there are no other constraints.
2 Size of the value
let a = 5;
let _b: u16 = a;
println!("{}", std::mem::____(&a)); // 2
let a = 5;
let _b: u16 = a;
println!("{}", std::mem::size_of_val(&a)); // 2
Explanation: size_of_val gives a value's size in bytes.
3 Code and inferred type
| Term | Meaning |
|---|---|
let x = 5; |
i32 |
let y = 2.0; |
f64 |
let a = 5; let b: u16 = a; |
a: u16 |
Vec::new() + push('ç') |
Vec<char> |