Error E0615 de Rust: attempted to take value of method (método usado como campo)
E0615 significa: escribiste valor.algo sin paréntesis, pero algo es un método, no un campo. En Rust, un método solo se ejecuta cuando lo llamas con (), aunque no reciba ningún argumento. Este error es muy común si vienes de C#, JavaScript o Python, donde .Count, .length o una propiedad parecen campos normales. La solución casi siempre ocupa dos caracteres. (Esta página forma parte de Errores del compilador de Rust explicados.)
El mensaje de error
Sección titulada «El mensaje de error»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` is a method | ^^^ method, not a field |help: use parentheses to call the method |3 | println!("{} has {} letters", name, name.len()); // ❌ `len` is a method | ++“Attempted to take value of method” quiere decir “intentaste tomar el valor de un método”. La etiqueta method, not a field significa “es un método, no un campo”, y el help te dice que uses paréntesis para llamarlo.
Este es el programa que lo produce:
fn main() { let name = String::from("Ferris"); println!("{} has {} letters", name, name.len); // ❌ `len` is a method}Qué significa
Sección titulada «Qué significa»Lee el titular desde el final: on type String es el tipo en el que Rust buscó, y method len es lo que encontró ahí. O sea, Rust sí encontró len. Lo que pasa es que no es un valor que puedas leer como un campo. Es un trozo de código que tiene que ejecutarse.
La etiqueta method, not a field y los ++ debajo de () en el help dicen exactamente eso: añade los paréntesis y listo.
Piensa en una máquina expendedora. Un campo es una etiqueta impresa en la máquina (“Máquina n.º 12”): solo tienes que leerla. Un método es un botón (“Devolver el cambio”): no pasa nada hasta que lo pulsas. name.len señala el botón. name.len() lo pulsa.
Por qué Rust hace esto
Sección titulada «Por qué Rust hace esto»Rust separa de forma estricta los campos y los métodos. Un campo es un dato guardado dentro del struct. Un método es una función definida en un bloque impl que recibe self. Un campo se lee con valor.campo y un método se llama con valor.metodo(). Mira Añadir comportamiento con métodos.
Muchos lenguajes difuminan esta línea con las propiedades: list.Count en C# o text.length en JavaScript parecen campos, pero por detrás ejecutan código. Rust no tiene propiedades, y es a propósito. Cuando ves (), sabes que se ejecuta código y que puede tardar; cuando no los ves, sabes que es una simple lectura de un dato guardado. No hay nada oculto.
Un struct puede incluso tener un campo y un método con el mismo nombre, como un campo privado balance y un método público balance(). Eso solo es posible porque Rust nunca adivina cuál de los dos querías: sin paréntesis es el campo, con paréntesis es el método.
Cómo solucionarlo
Sección titulada «Cómo solucionarlo»Solución 1: Añade los paréntesis
Sección titulada «Solución 1: Añade los paréntesis»Elige esta casi siempre. Haz lo que dice la línea help: y llama al método. Funciona igual con tus propios métodos (como total en un carrito de la compra) que con los de la biblioteca estándar, como len, is_empty, trim y count:
struct Item { price: u32, // en 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!("{} tiene {} letras", name, name.len()); // ✅ llamado
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()); // ✅ llamado }}Salida:
Ferris tiene 6 letrasTotal: 600 centavosSi el método necesita argumentos, rustc te muestra dónde van con un _ de relleno. Para s.contains, el help dice s.contains(_): pon ahí lo que estás buscando, por ejemplo s.contains("world"). Si no sabes bien qué necesita un método, el siguiente error de rustc (E0061) te dirá cuántos argumentos recibe.
Solución 2: Pasa el método como función, no valor.metodo
Sección titulada «Solución 2: Pasa el método como función, no valor.metodo»Elige esta cuando no querías llamar al método en ese momento, sino dárselo a otra cosa, como .map() o sort_by_key. Escribir .map(words[0].len) también da E0615. Tienes dos buenas opciones: una closure corta que llame al método, o la ruta completa del método, String::len, que funciona como el nombre de una función:
fn main() { let words = vec![String::from("crab"), String::from("ferris"), String::from("rust")];
// una closure que llama al método en cada elemento let lengths: Vec<usize> = words.iter().map(|w| w.len()).collect(); println!("{:?}", lengths);
// la ruta del método funciona como el nombre de una función 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);}Salida:
[4, 6, 4][4, 6, 4]["crab", "rust", "ferris"]Las palabras se quedan en inglés porque el ejemplo depende de su longitud. String::len funciona aquí porque iter() te da elementos &String, y String::len recibe un &String. Cuando los tipos no encajan exactamente, la closure |w| w.len() es la opción fácil que siempre funciona.
Solución 3: Conviértelo en un campo, si de verdad es un dato guardado
Sección titulada «Solución 3: Conviértelo en un campo, si de verdad es un dato guardado»Elige esta cuando el error está en tu propio struct y te das cuenta de que el valor debería estar guardado sin más. Es una pregunta de diseño: ¿campo o método?
- Hazlo campo cuando el valor se da una vez y no depende de nada más: un
id, unname, una fechacreated_at. - Hazlo método cuando el valor se calcula a partir de otros datos: un
totala partir de los artículos, unareaa partir del ancho y el alto, unlena partir del contenido.
Un campo total guardado se quedaría desactualizado en cuanto alguien añadiera un artículo y se olvidara de actualizarlo. Un método total() se calcula de nuevo cada vez, así que nunca puede estar mal. Aquí id es un campo y total es un método, y puedes ver que el método sigue siendo correcto cuando el pedido cambia:
mod shop { pub struct Order { pub id: u32, // guardado: se asigna una vez y se lee con order.id prices: Vec<u32>, // privado: solo cambia a través de 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: siempre coincide con los precios, nunca se queda viejo 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 {}: {} artículos, {} centavos", order.id, order.item_count(), order.total());
order.add(50); println!("Pedido {}: {} artículos, {} centavos", order.id, order.item_count(), order.total());}Salida:
Pedido 17: 2 artículos, 350 centavosPedido 17: 3 artículos, 400 centavosHay un punto intermedio que verás en muchas bibliotecas: un campo privado más un método público con el mismo nombre (un “getter”). El resto del código puede leer el valor con acc.balance(), pero no puede cambiarlo directamente. Si escribes acc.balance desde fuera del módulo, obtienes un error un poco distinto, E0616 “field balance of struct Account is private” (el campo balance del struct Account es privado), con la pista a method `balance` also exists, call it with parentheses (también existe un método balance, llámalo con paréntesis). La solución es la misma: añade (). Mira Todo es privado por defecto.
Dónde lo verás normalmente
Sección titulada «Dónde lo verás normalmente»Costumbres de otros lenguajes. name.len, list.is_empty, text.trim y words.iter().count dan todos E0615. En Rust todos son métodos, así que todos necesitan (). Solución: name.len(), list.is_empty(), etc. Mira Métodos de cadena útiles.
len en un Vec. scores.len es la única excepción al mensaje: obtienes E0616, “field len of struct Vec is private” (el campo len del struct Vec es privado), porque Vec de verdad tiene un campo oculto llamado len. Aun así, rustc añade help: a method `len` also exists, call it with parentheses. Solución: scores.len(). (scores.is_empty da el E0615 normal.) Mira Vectores.
Un método que cambia algo. counter.increment; solo en una línea también da E0615, aunque no quisieras ningún valor. Sin () no se ejecuta nada. Solución: counter.increment();.
Al revés: llamar a un campo como si fuera un método. Si name es un campo, user.name() da E0599 con la etiqueta field, not a method (es un campo, no un método) y help: remove the arguments (quita los argumentos). Solución: user.name. Y si el campo guarda una closure, como on_click: Box<dyn Fn() -> String>, rustc dice surround the field access with parentheses (rodea el acceso al campo con paréntesis): escribe (button.on_click)() para llamarla.
Errores relacionados
Sección titulada «Errores relacionados»- E0609: no field
xon typeT: el nombre después del punto no es ni un campo ni un método de ese tipo. Normalmente es un error al escribir el nombre o unOptionque hay que desempaquetar. - E0599: no method named x found: la dirección contraria,
user.name()cuandonamees un campo, o un método que no existe. - E0616: field is private:
scores.lenen unVec, o un campo privado con un getter público del mismo nombre. Llama al método. - E0061: wrong number of arguments: añadiste los
(), pero el método necesita argumentos. - E0610: primitive type doesn’t have fields:
.algosobre un número, unboolo unchar. - 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. Te aparece "attempted to take value of method is_empty on type String". ¿Cuál es la solución?
2. ¿Cuál de estos debería ser normalmente un método y no un campo guardado?
3. Quieres la longitud de cada palabra: words.iter().map(???). ¿Qué funciona?
Puntuación: 0 / 3
Para leer más
Sección titulada «Para leer más»- E0615 — Rust error codes index (en inglés): la explicación oficial de este error.
- Method Syntax — El libro de Rust (en inglés): cómo se definen y se llaman los métodos, y los getters que comparten nombre con un campo. También existe una traducción al español de la comunidad del libro.
- Defining and Instantiating Structs — El libro de Rust (en inglés): los campos, y cómo leerlos con la notación de punto.
- Method call expressions — The Rust Reference (en inglés): las reglas exactas de
valor.metodo(). - Methods — Rust by Example (en inglés): ejemplos cortos y ejecutables de métodos y funciones asociadas.