Skip to content

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.

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 item
2 | 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 resolution
help: 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"]);
}

rustc points at three places:

  1. The - under T on line 1: “type parameter from outer item”. This is the T that belongs to print_all.
  2. The ^ under T on line 2: “use of generic parameter from outer item”. The inner function show tries to use that T.
  3. The ---- under show: “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.

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.

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
- 7
▶ Try it Yourself

The 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.

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: apples
fruit: pears
▶ Try it Yourself

Closures 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 resolution
help: 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 items
▶ Try it Yourself

For 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.

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).

  • E0411: Self used outside any impl or trait, for example in a top-level fn new() -> Self.
  • E0277: the trait bound is not satisfied, what you get after fn show<T> without copying T: 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 fn uses a local variable of the outer function, shown above.
  • All compiler errors: the full list of error pages.

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