Erro E0411 do Rust: cannot find type Self in this scope (Self fora de um impl)
O E0411 quer dizer que você escreveu Self num lugar onde o Rust não consegue saber o que ele representa. Self é um atalho para “o tipo de que este bloco impl (ou trait) trata”, então ele só funciona dentro de um impl, de um trait ou de uma definição de tipo. A causa de costume é um construtor como fn new() -> Self escrito no nível do arquivo, ou um método que você copiou para fora do seu bloco impl. É um erro comum e rápido de corrigir. Ao contrário do E0412, que virou E0425 no Rust 1.93, este código não mudou: o rustc 1.97 continua mostrando E0411. Esta página faz parte do guia de erros do compilador.
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0411]: cannot find type `Self` in this scope --> src/main.rs:5:21 |5 | fn new_counter() -> Self { // ❌ `Self` fora de um `impl` | ----------- ^^^^ `Self` is only available in impls, traits, and type definitions | | | `Self` not allowed in a functionEm português: “não foi possível encontrar o tipo Self neste escopo”. O rustc explica que Self só existe em impls, traits e definições de tipo, e que ele não é permitido numa função.
Este é o programa que gera o erro:
struct Counter { count: u32,}
fn new_counter() -> Self { // ❌ `Self` fora de um `impl` Counter { count: 0 }}
fn main() { let c = new_counter(); println!("{}", c.count);}O que significa
Seção intitulada “O que significa”O rustc aponta para duas coisas na linha 5:
- O
^^^^embaixo deSelf: “Selfis only available in impls, traits, and type definitions” (Selfsó está disponível em impls, traits e definições de tipo). Essa é a regra, numa linha. - O
-----embaixo denew_counter: “Selfnot allowed in a function” (Selfnão é permitido numa função). Este é o motivo aqui:new_counteré uma função comum, que não faz parte de nenhumimpl.
Você pode até saber que new_counter devolve um Counter, porque acabou de escrever Counter { count: 0 }. Mas o Rust não lê o corpo da função para adivinhar o que Self significa. Self só ganha sentido a partir de um impl Counter { ... } ou trait ... { ... } em volta, e aqui não há nenhum.
É como a palavra “aqui” num post-it. Num mapa, “você está aqui” faz sentido. Num bilhete largado na mesa da cozinha, ninguém sabe onde é “aqui”.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”Self não é um tipo por si só. Ele é um marcador que cada impl ou trait preenche: dentro de impl Counter, Self quer dizer Counter; dentro de impl Timer, quer dizer Timer; dentro de um trait, quer dizer “o tipo que implementar este trait, seja ele qual for”. É isso que o torna útil: você pode renomear a struct, ou copiar um método para outro impl, e o Self acompanha.
Uma função solta não pertence a nenhum tipo, então não há nada para preencher. O Rust até poderia tentar adivinhar pelo corpo, mas aí uma assinatura dependeria do código dentro dela, e o Rust verifica as assinaturas por si sós, de propósito. Veja em Structs o lugar de costume de um fn new() -> Self.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Mova a função para dentro de um bloco impl
Seção intitulada “Correção 1: Mova a função para dentro de um bloco impl”Escolha esta na maioria das vezes. Uma função que cria um tipo ou trabalha com ele pertence ao bloco impl desse tipo, e lá o Self funciona do jeito que você esperava. Chame-a com 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);}Saída:
2Dentro do impl, você pode usar Self tanto como tipo (-> Self) quanto para criar um valor (Self { count: 0 }). Veja Structs.
Correção 2: Escreva o nome do tipo no lugar de Self
Seção intitulada “Correção 2: Escreva o nome do tipo no lugar de Self”Escolha esta quando a função deve continuar sendo uma função solta, por exemplo uma função auxiliar que cria vários tipos, ou que mora em outro módulo. Basta escrever o tipo de verdade, Counter, onde você tinha escrito 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);}Saída:
100Esta também é a correção para um fn reset(c: &mut Self) copiado para fora de um impl: todo Self na assinatura e no corpo vira Counter.
Correção 3: Use um tipo genérico se você queria dizer “qualquer tipo”
Seção intitulada “Correção 3: Use um tipo genérico se você queria dizer “qualquer tipo””Escolha esta quando você usou Self para dizer “o tipo que quem chama quiser”, que é trabalho para um T genérico, e não para Self. Declare <T> com os traits de que a função precisa. Aqui, T: Default deixa a função criar um valor inicial de qualquer 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);}Saída:
(0, 0)("", "")Se você quer que cada tipo decida como é criado, coloque a função num trait: trait Reset { fn fresh() -> Self; }. Dentro de um trait, Self quer dizer “o tipo que o implementa”. Veja Genéricos e Traits.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Self { ... } no main ou numa função solta. let c = Self { count: 0 }; dá E0411 com uma primeira linha um pouco diferente: cannot find struct, variant or union type `Self` in this scope (não foi encontrado o tipo struct, variante ou union Self neste escopo). Correção: escreva Counter { count: 0 }, ou chame Counter::new().
Uma função auxiliar dentro de um método. Dentro de impl Counter, um método que contém a sua própria fn helper() -> Self recebe outro código, o E0401: can't use `Self` from outer item (não dá para usar o Self do item de fora). Uma função dentro de outra função não herda o impl de fora. Correção: escreva Counter na função de dentro, ou use uma closure, ou leve helper para o impl como um método próprio.
Confundir Self com self. Self com maiúscula é o tipo; self com minúscula é o valor em que um método é chamado. Usar self fora de um método é outro erro, o E0424. A correção para os dois: confira se o código está dentro do bloco impl certo.
Erros relacionados
Seção intitulada “Erros relacionados”- E0424:
self(minúsculo, o valor) usado fora de um método. - E0425: não foi encontrado um valor, uma função ou (desde o Rust 1.93) um tipo com um nome comum.
- E0412: o código antigo para “cannot find type”, hoje mostrado como E0425.
- E0405: não foi encontrado um trait, normalmente por falta de uma linha
use. - E0401: o
Selfde umimplde fora usado dentro de uma função aninhada, mostrado acima. - Todos os erros do compilador: a lista completa de páginas de erro.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. Onde você pode usar Self como tipo?
2. fn make_user() -> Self no nível do arquivo dá E0411. Qual é a correção de costume?
3. Dentro de impl Counter, o que Self { count: 0 } cria?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0411 — Rust error codes index (em inglês): a explicação oficial do que
Selfrepresenta, e por que ele só funciona num impl, trait ou definição de tipo. - Method Syntax — The Rust Book (em inglês): funções associadas como
fn square(size: u32) -> Self, e como oSelffunciona numimpl. - The
Selfkeyword — documentação da biblioteca padrão (em inglês): o queSelfsignifica em impls, traits e definições de tipo. Selfin paths — The Rust Reference (em inglês): as regras exatas, incluindo por que itens aninhados não podem usar oSelfde fora.