Erro E0599 do Rust: no method named X found (método não encontrado)
O E0599 quer dizer que você chamou um método que o Rust não encontra naquele tipo. É muito comum, e a causa costuma ser uma de poucas: um trait que você não importou, um Option que você não abriu, um Vec tratado como se fosse um iterador ou um simples erro de digitação. A boa notícia é que as linhas help: do rustc muitas vezes dizem exatamente o que fazer. Para os outros erros desta série, veja Erros do compilador Rust.
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0599]: no method named `write_all` found for struct `Stdout` in the current scope --> src/main.rs:5:9 |5 | out.write_all(b"Server started\n").unwrap(); | ^^^^^^^^^ | = note: the method is available for `Stdout` here | = help: items from traits can only be used if the trait is in scopehelp: trait `Write` which provides `write_all` is implemented but not in scope; perhaps you want to import it |1 + use std::io::Write; |Em português: “nenhum método chamado write_all encontrado para a struct Stdout no escopo atual”. O compilador explica que o método vem de um trait, o Write, que não está no escopo, e sugere a linha use que falta.
Este é o programa que gera o erro:
use std::io;
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}O que significa
Seção intitulada “O que significa”O ^^^^ marca o nome do método, write_all, e a primeira linha diz em qual tipo o Rust procurou: Stdout. Então a mensagem quer dizer: “olhei em Stdout e não achei nenhum método chamado write_all que eu possa usar aqui”.
O tipo nessa primeira linha é a pista mais útil da mensagem. Se ali aparecer Option<T>, Result<T, E>, Vec<_> ou um parâmetro de tipo T quando você esperava outra coisa, você já sabe qual das correções abaixo precisa.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”Em Rust, muitos métodos não pertencem ao tipo em si. Eles vêm de um trait. write_all vem do trait Write, e Stdout o implementa. Só que os métodos de um trait só funcionam num arquivo que tem o trait no escopo, normalmente com uma linha use. É isso que significa “items from traits can only be used if the trait is in scope” (itens de traits só podem ser usados se o trait estiver no escopo).
Essa regra deixa o código previsível. Dois crates podem, cada um, acrescentar um método chamado write_all ao mesmo tipo por meio de traits diferentes. Se todo trait estivesse sempre ativo, não daria para saber a qual deles uma chamada se refere. Com a regra, só contam os traits que você importou.
As outras causas vêm dos tipos rigorosos do Rust. Um Option<&str> não é um &str, então não tem os métodos de &str. Um T genérico pode ser qualquer tipo, então o Rust só deixa você chamar os métodos que os bounds (restrições) de T garantem.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Importe o trait
Seção intitulada “Correção 1: Importe o trait”Escolha esta quando o help disser “items from traits can only be used if the trait is in scope”. Acrescente a linha use que o rustc sugere.
use std::io::{self, Write};
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}Saída:
Server startedO texto ficou em inglês de propósito: um literal b"..." só aceita caracteres ASCII, então nada de acentos ali.
O mesmo acontece com o crate rand. Sem o import, rng.random_range(1..=6) falha, e o rustc diz qual trait trazer:
help: trait `RngExt` which provides `random_range` is implemented but not in scope; perhaps you want to import it |1 + use rand::RngExt;Atenção: no rand 0.10 o trait se chama RngExt. Tutoriais mais antigos dizem use rand::Rng, e no rand 0.10 esse import dá exatamente este mesmo erro. Siga a linha help:, não o tutorial.
Correção 2: Tire o valor de dentro do Option ou do Result primeiro
Seção intitulada “Correção 2: Tire o valor de dentro do Option ou do Result primeiro”Escolha esta quando o tipo no erro for Option<T> ou Result<T, E>. O valor que você quer está lá dentro, e é preciso tirá-lo antes de chamar os métodos dele.
error[E0599]: no method named `to_uppercase` found for enum `Option<T>` in the current scope --> src/main.rs:4:39 |4 | println!("First guest: {}", first.to_uppercase()); | ^^^^^^^^^^^^ method not found in `Option<&&str>`O compilador avisa que o método não existe em Option<&&str>. first() devolve um Option, porque a lista pode estar vazia. O rustc sugere .expect(...), que funciona mas derruba o programa com None. Tratar os dois casos costuma ser melhor:
fn main() { let guests = vec!["ana", "bo", "chen"];
match guests.first() { Some(name) => println!("Primeiro convidado: {}", name.to_uppercase()), None => println!("Ainda não há convidados"), }
let shout = guests.last().map(|name| name.to_uppercase()); println!("Último convidado: {:?}", shout);}Saída:
Primeiro convidado: ANAÚltimo convidado: Some("CHEN").map() roda o seu código no valor de dentro e mantém o Option em volta. Para um Result (por exemplo, o de .parse()), use match, .unwrap_or(...) ou ? dentro de uma função que retorna Result. Veja Option e Result.
Correção 3: Chame .iter() no Vec
Seção intitulada “Correção 3: Chame .iter() no Vec”Escolha esta quando você chama .map(), .filter() ou outro método de iterador direto num Vec. Aqui o erro tem outra cara:
error[E0599]: the method `map` exists for struct `Vec<{integer}>`, but its trait bounds were not satisfied --> src/main.rs:3:35 |3 | let curved: Vec<i32> = scores.map(|s| s + 5).collect(); | ^^^ | = note: the following trait bounds were not satisfied: `Vec<{integer}>: Iterator`Em português: “o método map existe para Vec<{integer}>, mas os trait bounds dele não foram satisfeitos”. Para alguns métodos, como filter, a mensagem é mais amigável. O rustc diz que o Vec<i32> “is not an iterator” (não é um iterador) e acrescenta help: call `.into_iter()` first. Mesma causa, mesma correção.
Vec<{integer}>: Iterator “não é satisfeito” porque um Vec é uma coleção, não um iterador. Peça um iterador a ele com .iter() (empresta os itens) ou .into_iter() (toma os itens):
fn main() { let scores = vec![70, 85, 92]; let curved: Vec<i32> = scores.iter().map(|s| s + 5).collect(); println!("{:?}", curved);}Saída:
[75, 90, 97]Correção 4: Acrescente um trait bound ao T genérico
Seção intitulada “Correção 4: Acrescente um trait bound ao T genérico”Escolha esta quando o erro disser que o método não foi encontrado “for type parameter T” (para o parâmetro de tipo T). Dentro de uma função genérica, o Rust só sabe o que os bounds de T garantem. Um T sem nada não garante coisa alguma, então não tem métodos.
error[E0599]: no method named `to_string` found for type parameter `T` in the current scope --> src/main.rs:2:26 |1 | fn describe<T>(item: T) -> String { | - method `to_string` not found for this type parameter2 | format!("[{}]", item.to_string()) | ^^^^^^^^^ method cannot be called on `T` due to unsatisfied trait bounds |help: the following trait defines an item `to_string`, perhaps you need to restrict type parameter `T` with it: |1 | fn describe<T: ToString>(item: T) -> String { | ++++++++++O compilador diz que to_string não pode ser chamado em T e sugere restringir T com o trait ToString. Acrescente o bound sugerido. Agora só são aceitos tipos que podem virar string:
fn describe<T: ToString>(item: T) -> String { format!("[{}]", item.to_string())}
fn main() { println!("{}", describe(42)); println!("{}", describe("pronto"));}Saída:
[42][pronto]Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”- Um erro de digitação ou um método de outra linguagem.
tasks.push_back(...)numVecdáhelp: you might have meant to use `push`, etasks.lenght()dáhelp: there is a method `len` with a similar name. Correção: use o nome que o rustc sugere. - Chamar um
Type::new()que você nunca escreveu. O Rust não dá construtores de graça:Account::new("Ana", 100)falha comno associated function or constant named `new` found for struct `Account`. Correção: acrescenteimpl Account { fn new(owner: &str, balance: i64) -> Self { ... } }ou crie a struct direto comAccount { owner: ..., balance: ... }. Veja Structs. - Chamar uma função associada com ponto. Se
fn new() -> Selfnão tem parâmetroself,acc.new()falha com “this is an associated function, not a method” (isto é uma função associada, não um método). Correção: chame no tipo,Account::new().
Erros relacionados
Seção intitulada “Erros relacionados”- E0425: cannot find value in this scope: o próprio nome não está visível, em vez de um método de um tipo.
- E0277: trait bound not satisfied: falta a um tipo um trait de que uma função ou um operador precisa. Costuma aparecer junto com o E0599 em código genérico.
- E0308: mismatched types: você tem um
Option<T>onde se esperava umT, ou o contrário. - E0382: use of moved value: um erro comum logo depois de trocar
.iter()por.into_iter(). - Todos os erros do compilador: a lista completa, com um resumo curto de cada um.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. O rustc diz "items from traits can only be used if the trait is in scope". O que você deve fazer?
2. names.first().to_uppercase() falha com E0599 para Option<&&str>. Por quê?
3. Você chama scores.filter(...) num Vec<i32> e o rustc diz "Vec<i32> is not an iterator". Qual é a correção?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0599 — Rust error codes index (em inglês): a explicação oficial deste erro.
- Traits: Defining Shared Behavior — The Rust Book (em inglês): como os traits acrescentam métodos aos tipos e como funcionam os trait bounds.
- Processing a Series of Items with Iterators — The Rust Book (em inglês):
iter(),into_iter()e métodos de iterador comomap. Option— documentação da biblioteca padrão (em inglês): todos os métodos para tirar um valor de dentro de umOption.- The Rust prelude — documentação da biblioteca padrão (em inglês): os traits que estão sempre no escopo e por que
Writenão é um deles.