Type Inference
In this page:
Inference from Literals
When you write let x = 5;, Rust looks at the literal and defaults it to i32 without you writing the type. The compiler performs this inference at compile time -- there is no runtime type-checking involved.
Example: Inference from Literals
fn main() {
let count = 5;
let name = "Rustacean";
println!("{} appears {} times", name, count);
}
Login to try C/C++/Java/PHP code in the editor
Inference from Later Usage
Rust can also infer a variable's type from how it is used later in the code, not just from its initial value, as long as the usage is unambiguous.
Note: Here Rust infers Vec<i32> only after seeing the first push(1) call.
Example: Inference from Later Usage
fn main() {
let mut numbers = Vec::new();
numbers.push(1);
numbers.push(2);
println!("{:?}", numbers);
}
Login to try C/C++/Java/PHP code in the editor
Function Signatures Need Explicit Types
Unlike local variables, function parameters and return types are never inferred -- they must always be written out explicitly. This makes function signatures a reliable, self-documenting contract.
Example: Function Signatures Need Explicit Types
fn double(n: i32) -> i32 {
n * 2
}
fn main() {
println!("Doubled: {}", double(21));
}
Login to try C/C++/Java/PHP code in the editor
When Inference Fails
Sometimes the compiler cannot determine a type on its own, such as when a generic parsing method could produce several different types. In that case you must supply an explicit annotation to resolve the ambiguity.
Example: When Inference Fails
fn main() {
let parsed: i32 = "42".parse().unwrap();
println!("Parsed as i32: {}", parsed);
}
Login to try C/C++/Java/PHP code in the editor
- Believing Rust is dynamically typed because you rarely write type annotations -- every value still has one fixed type, just inferred.
- Leaving out a type annotation in a case where the compiler genuinely cannot infer it, leading to a compile error.
- Assuming inference works across function boundaries -- function parameters and return types must always be explicitly annotated.
- Rust infers types from context, such as literal values, later usage, or return values.
- Every value still has exactly one concrete type at compile time -- inference does not make Rust dynamically typed.
- Function signatures always require explicit parameter and return types, even though local variables often don't.
- When inference is ambiguous, the compiler reports an error asking for an explicit annotation.
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: