Rust Error E0401: Can't Use Generic Parameters From Outer Item
E0401 means a function written inside another function tried to use the outer one’s generic type, like T, or the Self of the impl it sits in. It feels like it should work, because the inner function is right there inside the outer one. But in Rust, a nested fn is a separate item that can’t see the outer T. It’s a common surprise when you tidy up a generic function by pulling a helper inside it, and it takes a minute to fix. It’s part of the compiler errors guide.
The error message
Section titled “The error message”error[E0401]: can't use generic parameters from outer item --> src/main.rs:2:20 |1 | fn print_all<T: std::fmt::Display>(items: &[T]) { | - type parameter from outer item2 | fn show(item: &T) { // ❌ inner `fn` can't see the outer `T` | ---- ^ use of generic parameter from outer item | | | generic parameter used in this inner function | = note: nested items are independent from their parent item for everything except for privacy and name resolutionhelp: try introducing a local generic parameter here |2 | fn show<T>(item: &T) { // ❌ inner `fn` can't see the outer `T` | +++This is the program that produces it:
fn print_all<T: std::fmt::Display>(items: &[T]) { fn show(item: &T) { // ❌ inner `fn` can't see the outer `T` println!("- {}", item); }
for item in items { show(item); }}
fn main() { print_all(&["apples", "pears"]);}What it means
Section titled “What it means”rustc points at three places:
- The
-underTon line 1: “type parameter from outer item”. This is theTthat belongs toprint_all. - The
^underTon line 2: “use of generic parameter from outer item”. The inner functionshowtries to use thatT. - The
----undershow: “generic parameter used in this inner function”. This is the function that isn’t allowed to.
The note: says the rule in one line: nested items are independent from their parent. Putting fn show inside print_all only hides its name from the rest of the file. It does not give show access to anything that belongs to print_all: not its T, not its parameters, not its local variables.
It’s like a guest room in a shared house. The room is inside the house, but the guest doesn’t get a key to your bedroom just because they sleep down the hall.
Why Rust does this
Section titled “Why Rust does this”A generic function like print_all<T> is a template. Rust makes a separate copy for each T you call it with: one for &str, one for i32, and so on. A nested fn, though, is compiled once, as its own item, exactly as if you had written it at the top of the file. So inside show, there’s no single T it could mean.
Rust could have made nested functions copy themselves along with their parent, but that would make them behave very differently from every other fn. Instead, the rule is simple: an inner fn only knows what you give it, through its own generic parameters and arguments. If you want something that does see the surrounding code, Rust has closures for that. See Generics and Closures.
How to fix it
Section titled “How to fix it”Fix 1: Give the inner function its own generic parameter
Section titled “Fix 1: Give the inner function its own generic parameter”Choose this most of the time. Declare <T> on the inner function too, with the same bounds it needs. rustc’s help suggests fn show<T>, but if you add only <T>, you get a new error, E0277 (`T` doesn't implement `std::fmt::Display`), because the new T has no bounds yet. Copy the bounds over:
use std::fmt::Display;
fn print_all<T: Display>(items: &[T]) { fn show<T: Display>(item: &T) { println!("- {}", item); }
for item in items { show(item); }}
fn main() { print_all(&["apples", "pears"]); print_all(&[3, 7]);}Output:
- apples- pears- 3- 7The inner T is a new parameter that happens to have the same name. When print_all calls show(item), Rust fills it in with the outer T. You could call it U to make that clearer.
Fix 2: Use a closure instead
Section titled “Fix 2: Use a closure instead”Choose this when the helper is small, or when it needs the outer function’s variables as well. A closure is not a separate item, so it sees everything around it: the outer T, the function’s parameters, and its local variables. Here the closure also uses label, which a nested fn could never reach:
use std::fmt::Display;
fn print_all<T: Display>(label: &str, items: &[T]) { let show = |item: &T| println!("{}: {}", label, item);
for item in items { show(item); }}
fn main() { print_all("fruit", &["apples", "pears"]);}Output:
fruit: applesfruit: pearsClosures can’t be generic on their own, but they don’t need to be here: inside print_all<T>, &T already means one concrete type for each copy of the function. See Closures.
Fix 3: Move the function out (or into the impl)
Section titled “Fix 3: Move the function out (or into the impl)”Choose this when the helper is useful on its own, or when the error is about Self. Inside a method, a nested fn can’t use Self either, because it’s outside the impl in the same way:
error[E0401]: can't use `Self` from outer item --> src/main.rs:7:24 |5 | impl Inventory { | ---- `Self` type implicitly declared here, by this `impl`6 | fn report(&self) {7 | fn count(inv: &Self) -> usize { // ❌ inner `fn` can't see `Self` | ----- ^^^^ use of `Self` from outer item | | | `Self` used in this inner function | = note: nested items are independent from their parent item for everything except for privacy and name resolutionhelp: refer to the type directly here instead |7 - fn count(inv: &Self) -> usize { // ❌ inner `fn` can't see `Self`7 + fn count(inv: &Inventory) -> usize { // ❌ inner `fn` can't see `Self` |The broken program:
struct Inventory { items: Vec<String>,}
impl Inventory { fn report(&self) { fn count(inv: &Self) -> usize { // ❌ inner `fn` can't see `Self` inv.items.len() } println!("{} items", count(self)); }}
fn main() { let inv = Inventory { items: vec!["rope".to_string()] }; inv.report();}rustc’s help (write &Inventory) works. But usually the cleaner fix is to move count up one level, so it becomes a method of its own. There, Self and self work as usual:
struct Inventory { items: Vec<String>,}
impl Inventory { fn count(&self) -> usize { self.items.len() }
fn report(&self) { println!("{} items", self.count()); }}
fn main() { let inv = Inventory { items: vec!["rope".to_string(), "lamp".to_string()], }; inv.report();}Output:
2 itemsFor a generic helper like show, “moving it out” means a top-level fn show<T: Display>(item: &T), which other functions can reuse too. See Structs and Rust Functions.
Where you’ll usually see it
Section titled “Where you’ll usually see it”A struct or enum inside a generic function. fn group<T>(items: Vec<T>) with struct Pair { a: T, b: T } inside gives E0401 on each T. Fix: make the inner type generic too, struct Pair<T> { a: T, b: T }, or move it to the top level.
A const that depends on T. const SIZE: usize = std::mem::size_of::<T>(); inside a generic function is E0401 as well, because a const is an item too. Fix: use a let: let size = std::mem::size_of::<T>();.
An inner function that uses a local variable. That’s the same idea with a value instead of a type, but a different code: E0434 (can't capture dynamic environment in a fn item). Fix: pass the value as an argument, or use a closure (Fix 2).
Related errors
Section titled “Related errors”- E0411:
Selfused outside anyimplor trait, for example in a top-levelfn new() -> Self. - E0277: the trait bound is not satisfied, what you get after
fn show<T>without copyingT: Display. - E0425: cannot find a value or type, for example a type you never declared.
- E0107: wrong number of generic arguments, another generics mistake.
- E0434: an inner
fnuses a local variable of the outer function, shown above. - All compiler errors: the full list of error pages.
Quick check
Section titled “Quick check”Quick check
1. Inside fn print_all<T>(...), why can't a nested fn show(item: &T) use T?
2. Which helper inside fn print_all<T: Display> can use the outer T and the outer local variables?
3. You follow rustc's help and write fn show<T>(item: &T), then print item with {}. What happens?
Score: 0 / 3
Read more
Section titled “Read more”- E0401 — Rust error codes index: the official explanation, with the three fixes: a local generic parameter, a closure, or moving the function out.
- Item declarations — The Rust Reference: the rule that an inner item doesn’t capture the outer function’s generic parameters, parameters or local variables.
- Generic Data Types — The Rust Book: how
<T>and trait bounds work on functions, structs and methods. - Closures — The Rust Book: how closures capture their environment, which nested functions can’t do.