error[E0308]: mismatched types — how to fix
error[E0308]: mismatched types
--> src/main.rs:4:18
|
4 | let n: u32 = "5";
| --- ^^^ expected `u32`, found `&str`
| |
| expected due to this
Quick fix: Read the expected X, found Y line and convert explicitly: .parse::<u32>()? for strings to numbers, .to_string()/String::from for &str→String, &s / .as_str() for String→&str, as/into()/try_into() between number types, Some(x) / Ok(x) for Option/Result. Remove a trailing ; if it found ().
What it means
The compiler inferred or was told one type for a spot (a variable annotation, a function parameter, a return type, a match arm) and the expression you put there has another. The expected ..., found ... label is the key. rustc --explain E0308 gives the official description.
Fix 1: expected (), found X — a semicolon or missing return
A block's value is its last expression without a semicolon. Adding ; turns it into a statement of type ().
fn double(x: i32) -> i32 {
x * 2; // error: expected `i32`, found `()`
}
Remove the semicolon (x * 2) or write return x * 2;.
The reverse: if without else has type (), so using its value fails:
let label = if n > 0 { "positive" }; // error
let label = if n > 0 { "positive" } else { "non-positive" };
Fix 2: String vs &str
let s: String = "hello"; // expected `String`, found `&str`
let s: String = "hello".to_string(); // or String::from("hello"), "hello".into()
fn greet(name: &str) {}
let owned = String::from("Ann");
greet(owned); // expected `&str`, found `String`
greet(&owned); // deref coercion: &String -> &str
greet(owned.as_str());
Comparing in a match on a String: match s.as_str() { "a" => ..., _ => ... }.
Fix 3: numbers of different types
Rust doesn't mix i32, u32, usize, f64 automatically:
let len: usize = v.len();
let n: i32 = 10;
let total = len + n; // error
let total = len + n as usize; // `as` truncates/wraps silently
let total = len + usize::try_from(n)?; // checked conversion
let x: f64 = n.into(); // lossless conversions via From/Into
Literals can be typed with a suffix: 10u64, 2.0f32.
Strings to numbers need parsing:
let n: u32 = "5".parse().expect("not a number");
let n: u32 = input.trim().parse()?; // trim the newline from read_line!
Fix 4: Option / Result wrapping
fn find() -> Option<i32> {
42 // expected `Option<i32>`, found integer
}
Wrap it: Some(42). For Result, Ok(value). The other direction — expected i32, found Option<i32> — means you must handle the None/Err case:
let v = map.get("k").copied().unwrap_or(0);
let v = text.parse::<i32>()?; // in a fn returning Result
if let Some(v) = maybe { ... }
Fix 5: references vs values
expected i32, found &i32 is common when iterating:
let v = vec![1, 2, 3];
let sum: i32 = v.iter().map(|x| x * 2).sum(); // fine (ops work on &i32)
let first: i32 = v.iter().next().unwrap(); // error: found `&i32`
let first: i32 = *v.iter().next().unwrap(); // dereference
let first: i32 = v[0]; // Copy types index by value
Use .copied() / .cloned() on iterators, or into_iter() to get owned values.
Fix 6: match / if arms with different types
All arms must produce the same type. Returning i32 in one arm and &str in another fails. Make them agree, or return an enum or Box<dyn Trait>. For closures or iterators with different concrete types, impl Trait in return position needs a single concrete type — use Box<dyn Iterator<Item = T>> when branches differ.
Last updated 2026-11-02.