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.
El mensaje de error
Sección titulada «El mensaje de error»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);}Qué significa
Sección titulada «Qué significa»rustc señala dos cosas en la línea 5:
- El
^^^^debajo deSelf: “Selfis only available in impls, traits, and type definitions” (Selfsolo existe en impls, traits y definiciones de tipos). Esa es la regla, en una línea. - El
-----debajo denew_counter: “Selfnot allowed in a function” (Selfno está permitido en una función). Este es el motivo aquí:new_counteres una función normal, no forma parte de ningúnimpl.
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í”.
Por qué Rust hace esto
Sección titulada «Por qué Rust hace esto»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.
Cómo solucionarlo
Sección titulada «Cómo solucionarlo»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:
2Dentro 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:
100Esta 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)("", "")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.
Dónde lo verás normalmente
Sección titulada «Dónde lo verás normalmente»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.
Errores relacionados
Sección titulada «Errores relacionados»- 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
Selfde unimplexterior 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 que aprendiste
Sección titulada «Comprueba lo que aprendiste»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
Para leer más
Sección titulada «Para leer más»- E0411 — Rust error codes index (en inglés): la explicación oficial de lo que representa
Self, y de por qué solo funciona en un impl, un trait o una definición de tipo. - Method Syntax — El libro de Rust (en inglés): funciones asociadas como
fn square(size: u32) -> Self, y cómo funcionaSelfen unimpl. También existe una traducción al español de la comunidad del libro. - The
Selfkeyword — documentación de la biblioteca estándar (en inglés): qué significaSelfen impls, traits y definiciones de tipos. Selfin paths — The Rust Reference (en inglés): las reglas exactas, incluido por qué los elementos anidados no pueden usar unSelfexterior.