← Back to Rust Course | Chapter 2: Variables & Types | Lesson 7 of 7

Type Inference

Rust is smart enough to figure out what kind of value you meant most of the time, so you often don't need to say it yourself.
Syntax
rust
let name = value;         // type inferred
let name: Type = expr.parse().unwrap();

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

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `count`, set to `5`
    let count = 5;
    // Declare an immutable variable `name`, set to `"Rustacean"`
    let name = "Rustacean";
    // Print "{} appears {} times" to the console, substituting in `name, count` (with a trailing newline)
    println!("{} appears {} times", name, count);
}

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

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare a mutable variable `numbers`, initialized to `Vec::new()`
    let mut numbers = Vec::new();
    // Append `1` to `numbers`
    numbers.push(1);
    // Append `2` to `numbers`
    numbers.push(2);
    // Print "{:?}" to the console, substituting in `numbers` (with a trailing newline)
    println!("{:?}", numbers);
}

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

markup
// Define the function `double` taking `n` and returning an integer
fn double(n: i32) -> i32 {
    n * 2
}

// Entry point: execution of the program starts here
fn main() {
    // Print "Doubled: {}" to the console, substituting in `double(21)` (with a trailing newline)
    println!("Doubled: {}", double(21));
}

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

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `parsed` (an integer), set to `"42".parse().unwrap()`
    let parsed: i32 = "42".parse().unwrap();
    // Print "Parsed as i32: {}" to the console, substituting in `parsed` (with a trailing newline)
    println!("Parsed as i32: {}", parsed);
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Believing Rust is dynamically typed because you rarely write type annotations -- every value still has one fixed type, just inferred.
  2. Leaving out a type annotation in a case where the compiler genuinely cannot infer it, leading to a compile error.
  3. Assuming inference works across function boundaries -- function parameters and return types must always be explicitly annotated.
Chapter Summary
  • 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:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.