Erro E0615 do Rust: attempted to take value of method (método sem parênteses)
O E0615 quer dizer: você escreveu valor.alguma_coisa sem parênteses, mas alguma_coisa é um método, não um campo. Em Rust, um método só roda quando você o chama com (), mesmo que ele não receba nenhum argumento. Esse erro é muito comum para quem vem de C#, JavaScript ou Python, onde .Count, .length ou uma property parecem campos normais. A correção quase sempre tem dois caracteres. (Esta página faz parte de Erros do compilador Rust explicados.)
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0615]: attempted to take value of method `len` on type `String` --> src/main.rs:3:46 |3 | println!("{} has {} letters", name, name.len); // ❌ `len` é um método | ^^^ method, not a field |help: use parentheses to call the method |3 | println!("{} has {} letters", name, name.len()); // ❌ `len` é um método | ++Em português: “tentou pegar o valor do método len no tipo String”. O rótulo diz “método, não um campo”, e a ajuda diz “use parênteses para chamar o método”.
Este é o programa que gera o erro:
fn main() { let name = String::from("Ferris"); println!("{} has {} letters", name, name.len); // ❌ `len` é um método}O que significa
Seção intitulada “O que significa”Leia a primeira linha de trás para frente: on type String é o tipo que o Rust olhou, e method len é o que ele encontrou ali. Ou seja, o Rust achou o len. Só que ele não é um valor que você lê como um campo. É um pedaço de código que precisa rodar.
O rótulo method, not a field e o ++ embaixo do () na ajuda dizem exatamente isso: coloque os parênteses e pronto.
Pense numa máquina de vender salgadinhos. Um campo é uma etiqueta impressa na máquina (“Máquina nº 12”): você só lê. Um método é um botão (“Mostrar meu troco”): nada acontece até você apertar. name.len aponta para o botão. name.len() aperta o botão.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”O Rust separa campos e métodos com rigor. Um campo é um dado guardado dentro da struct. Um método é uma função definida num bloco impl que recebe self. Você lê um campo com valor.campo e chama um método com valor.metodo(). Veja Adicionando comportamento com métodos.
Muitas linguagens misturam as duas coisas com properties (propriedades): list.Count em C# ou text.length em JavaScript parecem campos, mas rodam código por trás. O Rust não tem properties, e isso é de propósito. Quando você vê (), sabe que código vai rodar e pode levar tempo; quando não vê, sabe que é só a leitura de um dado guardado. Nada fica escondido.
Uma struct pode até ter um campo e um método com o mesmo nome, como um campo privado balance e um método público balance(). Isso só é possível porque o Rust nunca adivinha qual dos dois você quis: sem parênteses é o campo, com parênteses é o método.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Coloque os parênteses
Seção intitulada “Correção 1: Coloque os parênteses”Escolha esta quase sempre. Siga a linha help: e chame o método. Funciona igual para os seus próprios métodos (como total num carrinho de compras) e para os da biblioteca padrão, como len, is_empty, trim e count:
struct Item { price: u32, // em centavos qty: u32,}
struct Cart { items: Vec<Item>,}
impl Cart { fn total(&self) -> u32 { self.items.iter().map(|i| i.price * i.qty).sum() }}
fn main() { let name = String::from("Ferris"); println!("{} tem {} letras", name, name.len()); // ✅ chamado
let cart = Cart { items: vec![Item { price: 250, qty: 2 }, Item { price: 100, qty: 1 }], }; if !cart.items.is_empty() { println!("Total: {} centavos", cart.total()); // ✅ chamado }}Saída:
Ferris tem 6 letrasTotal: 600 centavosSe o método precisar de argumentos, o rustc mostra onde eles entram com um marcador _. Para s.contains, a ajuda mostra s.contains(_): preencha com o que você está procurando, como s.contains("world"). Se não tiver certeza do que o método precisa, o próximo erro do rustc (E0061) vai dizer quantos argumentos ele recebe.
Correção 2: Passe o método como função, não como valor.metodo
Seção intitulada “Correção 2: Passe o método como função, não como valor.metodo”Escolha esta quando você não queria chamar o método agora, e sim entregá-lo para outra coisa, como .map() ou sort_by_key. Escrever .map(words[0].len) também dá E0615. Você tem duas boas opções: uma closure curta que chama o método, ou o caminho completo do método, String::len, que funciona como o nome de uma função:
fn main() { let words = vec![String::from("crab"), String::from("ferris"), String::from("rust")];
// uma closure que chama o método em cada item let lengths: Vec<usize> = words.iter().map(|w| w.len()).collect(); println!("{:?}", lengths);
// o caminho do método funciona como o nome de uma função let same: Vec<usize> = words.iter().map(String::len).collect(); println!("{:?}", same);
let mut sorted = words.clone(); sorted.sort_by_key(|w| w.len()); println!("{:?}", sorted);}Saída:
[4, 6, 4][4, 6, 4]["crab", "rust", "ferris"]String::len funciona aqui porque iter() te dá itens &String, e String::len recebe um &String. Quando os tipos não batem exatamente, a closure |w| w.len() é a escolha fácil que sempre funciona.
Correção 3: Transforme em campo, se for mesmo um dado guardado
Seção intitulada “Correção 3: Transforme em campo, se for mesmo um dado guardado”Escolha esta quando o erro está na sua struct e você percebe que o valor deveria simplesmente ser guardado. É uma questão de design: campo ou método?
- Faça um campo quando o valor é definido uma vez e não depende de mais nada: um
id, umname, uma datacreated_at. - Faça um método quando o valor é calculado a partir de outros dados: um
totala partir dos itens, umaareaa partir da largura e da altura, umlena partir do conteúdo.
Um campo total guardado ficaria desatualizado no momento em que alguém acrescentasse um item e esquecesse de atualizá-lo. Um método total() é calculado de novo toda vez, então nunca fica errado. Aqui id é um campo e total é um método, e dá para ver que o método continua certo enquanto o pedido muda:
mod shop { pub struct Order { pub id: u32, // guardado: definido uma vez, lido com order.id prices: Vec<u32>, // privado: só muda pelos métodos }
impl Order { pub fn new(id: u32) -> Self { Order { id, prices: Vec::new() } }
pub fn add(&mut self, price: u32) { self.prices.push(price); }
// calculado: sempre bate com os preços, nunca fica desatualizado pub fn total(&self) -> u32 { self.prices.iter().sum() }
pub fn item_count(&self) -> usize { self.prices.len() } }}
use shop::Order;
fn main() { let mut order = Order::new(17); order.add(250); order.add(100); println!("Pedido {}: {} itens, {} centavos", order.id, order.item_count(), order.total());
order.add(50); println!("Pedido {}: {} itens, {} centavos", order.id, order.item_count(), order.total());}Saída:
Pedido 17: 2 itens, 350 centavosPedido 17: 3 itens, 400 centavosExiste um meio-termo que você vai ver em muitas bibliotecas: um campo privado mais um método público com o mesmo nome (um “getter”). O resto do código consegue ler o valor com acc.balance(), mas não consegue alterá-lo diretamente. Escrever acc.balance fora do módulo dá então um erro um pouco diferente, o E0616 “field balance of struct Account is private” (o campo balance da struct Account é privado), com a dica a method `balance` also exists, call it with parentheses (também existe um método balance, chame-o com parênteses). A correção é a mesma: coloque (). Veja Tudo é privado por padrão.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Hábitos de outras linguagens. name.len, list.is_empty, text.trim e words.iter().count dão E0615. Todos são métodos em Rust, então todos precisam de (). Correção: name.len(), list.is_empty() e assim por diante. Veja Métodos de string úteis.
len num Vec. scores.len é a única exceção à mensagem: você recebe o E0616, “field len of struct Vec is private”, porque o Vec tem mesmo um campo escondido chamado len. O rustc ainda acrescenta help: a method `len` also exists, call it with parentheses. Correção: scores.len(). (scores.is_empty dá o E0615 normal.) Veja Vetores.
Um método que altera alguma coisa. counter.increment; sozinho numa linha também dá E0615, mesmo que você não quisesse um valor. Sem (), nada roda. Correção: counter.increment();.
O contrário: chamar um campo como método. Se name é um campo, user.name() dá E0599 com o rótulo field, not a method (campo, não um método) e help: remove the arguments (remova os argumentos). Correção: user.name. E se o campo guarda uma closure, como on_click: Box<dyn Fn() -> String>, o rustc diz surround the field access with parentheses (coloque o acesso ao campo entre parênteses): escreva (button.on_click)() para chamá-la.
Erros relacionados
Seção intitulada “Erros relacionados”- E0609: no field
xon typeT: o nome depois do ponto não é nem campo nem método daquele tipo. Normalmente é um erro de digitação ou umOptionque precisa ser aberto. - E0599: no method named x found: a direção oposta,
user.name()quandonameé um campo, ou um método que não existe. - E0616: field is private:
scores.lennumVec, ou um campo privado com um getter público de mesmo nome. Chame o método. - E0061: wrong number of arguments: você colocou o
(), mas o método precisa de argumentos. - E0610: primitive type doesn’t have fields:
.alguma_coisanum número,boolouchar. - Todos os erros do compilador explicados
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. Aparece "attempted to take value of method is_empty on type String". Qual é a correção?
2. Qual destes normalmente deveria ser um método em vez de um campo guardado?
3. Você quer o tamanho de cada palavra: words.iter().map(???). O que funciona?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0615 — Rust error codes index (em inglês): a explicação oficial deste erro.
- Method Syntax — The Rust Book (em inglês): como métodos são definidos e chamados, e getters com o mesmo nome de um campo.
- Defining and Instantiating Structs — The Rust Book (em inglês): campos, e como lê-los com a notação de ponto.
- Method call expressions — The Rust Reference (em inglês): as regras exatas de
valor.metodo(). - Methods — Rust by Example (em inglês): exemplos curtos para rodar, com métodos e funções associadas.