Ir al contenido

Error E0411 de Rust: cannot find type Self in this scope (Self fuera de un impl)

E0411 significa que escribiste Self en un sitio donde Rust no sabe qué representa. Self es un atajo para “el tipo del que trata este bloque impl (o este trait)”, así que solo funciona dentro de un impl, de un trait o de una definición de tipo. La causa habitual es un constructor como fn new() -> Self escrito suelto en el archivo, o un método que copiaste fuera de su bloque impl. Es un error común y rápido de arreglar. A diferencia de E0412, que pasó a ser E0425 en Rust 1.93, este código no ha cambiado: rustc 1.97 sigue mostrando E0411. Forma parte de la guía de errores del compilador.

error[E0411]: cannot find type `Self` in this scope
--> src/main.rs:5:21
|
5 | fn new_counter() -> Self { // ❌ `Self` outside an `impl`
| ----------- ^^^^ `Self` is only available in impls, traits, and type definitions
| |
| `Self` not allowed in a function

“Cannot find type Self in this scope” quiere decir “no se encuentra el tipo Self en este ámbito”. Abajo te explicamos las dos etiquetas.

Este es el programa que lo produce:

struct Counter {
count: u32,
}
fn new_counter() -> Self { // ❌ `Self` outside an `impl`
Counter { count: 0 }
}
fn main() {
let c = new_counter();
println!("{}", c.count);
}

rustc señala dos cosas en la línea 5:

  1. El ^^^^ debajo de Self: “Self is only available in impls, traits, and type definitions” (Self solo existe en impls, traits y definiciones de tipos). Esa es la regla, en una línea.
  2. El ----- debajo de new_counter: “Self not allowed in a function” (Self no está permitido en una función). Este es el motivo aquí: new_counter es una función normal, no forma parte de ningún impl.

Puede que tú sepas que new_counter devuelve un Counter, porque acabas de escribir Counter { count: 0 }. Pero Rust no lee el cuerpo para adivinar qué significa Self. Self solo toma su significado de un impl Counter { ... } o trait ... { ... } que lo rodee, y aquí no hay ninguno.

Es como la palabra “aquí” en una nota adhesiva. En un mapa, “usted está aquí” tiene sentido. En una nota tirada en la mesa de la cocina, nadie sabe dónde es “aquí”.

Self no es un tipo por sí mismo. Es un marcador que cada impl o trait rellena: dentro de impl Counter, Self significa Counter; dentro de impl Timer, significa Timer; dentro de un trait, significa “el tipo que implemente este trait”. Eso es lo que lo hace útil: puedes cambiar el nombre del struct, o copiar un método a otro impl, y Self se adapta solo.

Una función libre no pertenece a ningún tipo, así que no hay nada con qué rellenarlo. Rust podría intentar adivinarlo a partir del cuerpo, pero entonces una firma dependería del código de dentro, y Rust comprueba las firmas por separado a propósito. Mira Funciones constructoras, el sitio habitual de fn new() -> Self.

Solución 1: Mueve la función a un bloque impl

Sección titulada «Solución 1: Mueve la función a un bloque impl»

Elige esta la mayoría de las veces. Una función que crea un tipo o trabaja con él va en el bloque impl de ese tipo, y ahí Self funciona como esperabas. Llámala con Counter::new():

struct Counter {
count: u32,
}
impl Counter {
fn new() -> Self {
Self { count: 0 }
}
fn increment(&mut self) {
self.count += 1;
}
}
fn main() {
let mut c = Counter::new();
c.increment();
c.increment();
println!("{}", c.count);
}

Salida:

2
▶ Pruébalo tú mismo

Dentro del impl, puedes usar Self como tipo (-> Self) y también para crear un valor (Self { count: 0 }). Mira Añadir comportamiento con métodos.

Solución 2: Escribe el nombre del tipo en lugar de Self

Sección titulada «Solución 2: Escribe el nombre del tipo en lugar de Self»

Elige esta cuando la función debe seguir siendo una función libre, por ejemplo una función auxiliar que crea varios tipos, o una que vive en otro módulo. Simplemente escribe el tipo real, Counter, donde habías puesto Self:

struct Counter {
count: u32,
}
fn new_counter(start: u32) -> Counter {
Counter { count: start }
}
fn reset(c: &mut Counter) {
c.count = 0;
}
fn main() {
let mut c = new_counter(10);
println!("{}", c.count);
reset(&mut c);
println!("{}", c.count);
}

Salida:

10
0
▶ Pruébalo tú mismo

Esta también es la solución para un fn reset(c: &mut Self) copiado fuera de un impl: cada Self de la firma y del cuerpo pasa a ser Counter.

Solución 3: Usa un tipo genérico si querías decir “cualquier tipo”

Sección titulada «Solución 3: Usa un tipo genérico si querías decir “cualquier tipo”»

Elige esta cuando usaste Self con el sentido de “el tipo que quiera quien llama”, que es trabajo para un genérico T, no para Self. Declara <T> con los traits que necesita la función. Aquí, T: Default deja que la función cree un valor inicial de cualquier tipo:

fn fresh_pair<T: Default>() -> (T, T) {
(T::default(), T::default())
}
fn main() {
let numbers: (u32, u32) = fresh_pair();
let words: (String, String) = fresh_pair();
println!("{:?}", numbers);
println!("{:?}", words);
}

Salida:

(0, 0)
("", "")
▶ Pruébalo tú mismo

Si quieres que cada tipo decida cómo se crea, pon la función en un trait: trait Reset { fn fresh() -> Self; }. Dentro de un trait, Self significa “el tipo que lo implementa”. Mira Genéricos y Definir un trait.

Self { ... } en main o en una función libre. let c = Self { count: 0 }; da E0411 con un titular un poco distinto: cannot find struct, variant or union type `Self` in this scope (no se encuentra el struct, la variante o la unión Self en este ámbito). Solución: escribe Counter { count: 0 }, o llama a Counter::new().

Una función auxiliar anidada dentro de un método. Dentro de impl Counter, un método que contiene su propia fn helper() -> Self recibe otro código, E0401: can't use `Self` from outer item (no se puede usar el Self del elemento exterior). Una función dentro de otra función no hereda el impl de fuera. Solución: escribe Counter en la función interior, usa un closure, o sube helper al impl como un método más.

Confundir Self con self. Self con mayúscula es el tipo; self con minúscula es el valor sobre el que se llama un método. Usar self fuera de un método es otro error, E0424. La solución para los dos: asegúrate de que el código está dentro del bloque impl correcto.

  • E0424: self (en minúscula, el valor) usado fuera de un método.
  • E0425: no se encuentra un valor, una función o (desde Rust 1.93) un tipo con un nombre normal.
  • E0412: el código antiguo de “cannot find type”, que ahora se muestra como E0425.
  • E0405: no se encuentra un trait, normalmente porque falta una línea use.
  • E0401: el Self de un impl exterior usado dentro de una función anidada, como viste arriba.
  • Todos los errores del compilador: la lista completa de páginas de errores.

Comprueba lo aprendido

1. ¿Dónde puedes usar Self como tipo?

2. fn make_user() -> Self suelto en el archivo da E0411. ¿Cuál es la solución habitual?

3. Dentro de impl Counter, ¿qué crea Self { count: 0 }?

Puntuación: 0 / 3