Skip to content

Rust Error E0615: Attempted to Take Value of Method

E0615 means: you wrote value.something without parentheses, but something is a method, not a field. In Rust, a method only runs when you call it with (), even when it takes no arguments. This one is very common if you come from C#, JavaScript or Python, where .Count, .length or a property look like plain fields. The fix is almost always two characters long. (This page is part of Rust compiler errors explained.)

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
| ++

This is the program that produces it:

fn main() {
let name = String::from("Ferris");
println!("{} has {} letters", name, name.len); // ❌ `len` is a method
}

Read the headline from the end: on type String is the type Rust looked at, and method len is what it found there. So Rust did find len. It just isn’t a value you can read like a field. It’s a piece of code that has to run.

The label method, not a field and the ++ under () in the help say exactly that: add the parentheses and you’re done.

Think of a vending machine. A field is a label printed on the machine (“Machine #12”): you just read it. A method is a button (“Show my change”): nothing happens until you press it. name.len points at the button. name.len() presses it.

Rust keeps fields and methods strictly apart. A field is data stored inside the struct. A method is a function defined in an impl block that takes self. You read a field with value.field and call a method with value.method(). See Adding behavior with methods.

Many languages blur this line with properties: list.Count in C# or text.length in JavaScript look like fields but run code behind the scenes. Rust doesn’t have properties on purpose. When you see (), you know code runs and may take time; when you don’t, you know it’s a plain read of stored data. Nothing is hidden.

A struct can even have a field and a method with the same name, like a private balance field and a public balance() method. That’s only possible because Rust never guesses which one you meant: no parentheses means the field, parentheses means the method.

Choose this almost every time. Follow the help: line and call the method. This works the same for your own methods (like total on a shopping cart) and for standard ones like len, is_empty, trim and count:

struct Item {
price: u32, // in cents
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!("{} has {} letters", name, name.len()); // ✅ called
let cart = Cart {
items: vec![Item { price: 250, qty: 2 }, Item { price: 100, qty: 1 }],
};
if !cart.items.is_empty() {
println!("Total: {} cents", cart.total()); // ✅ called
}
}

Output:

Ferris has 6 letters
Total: 600 cents
▶ Try it Yourself

If the method needs arguments, rustc shows where they go with a _ placeholder. For s.contains the help reads s.contains(_): fill in what you’re looking for, such as s.contains("world"). If you’re not sure what a method needs, rustc’s next error (E0061) will tell you how many arguments it takes.

Fix 2: Pass the method as a function, not value.method

Section titled “Fix 2: Pass the method as a function, not value.method”

Choose this when you didn’t want to call the method right now, but hand it to something else, like .map() or sort_by_key. Writing .map(words[0].len) gives E0615 too. You have two good options: a short closure that calls the method, or the method’s full path, String::len, which works like a function name:

fn main() {
let words = vec![String::from("crab"), String::from("ferris"), String::from("rust")];
// a closure that calls the method on each item
let lengths: Vec<usize> = words.iter().map(|w| w.len()).collect();
println!("{:?}", lengths);
// the method's path works like a function name
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);
}

Output:

[4, 6, 4]
[4, 6, 4]
["crab", "rust", "ferris"]
▶ Try it Yourself

String::len works here because iter() gives you &String items, and String::len takes a &String. When the types don’t line up exactly, the closure |w| w.len() is the easy choice that always works.

Fix 3: Make it a field, if it really is stored data

Section titled “Fix 3: Make it a field, if it really is stored data”

Choose this when the error is in your own struct and you realize the value should just be stored. This is a design question: field or method?

  • Make it a field when the value is given once and doesn’t depend on anything else: an id, a name, a created_at date.
  • Make it a method when the value is worked out from other data: a total from the items, an area from width and height, a len from the contents.

A stored total field would go out of date the moment someone adds an item and forgets to update it. A total() method is calculated fresh every time, so it can never be wrong. Here id is a field and total is a method, and you can see the method stays correct as the order changes:

mod shop {
pub struct Order {
pub id: u32, // stored: set once, read with order.id
prices: Vec<u32>, // private: only changed through methods
}
impl Order {
pub fn new(id: u32) -> Self {
Order { id, prices: Vec::new() }
}
pub fn add(&mut self, price: u32) {
self.prices.push(price);
}
// computed: always matches the prices, can't go stale
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!("Order {}: {} items, {} cents", order.id, order.item_count(), order.total());
order.add(50);
println!("Order {}: {} items, {} cents", order.id, order.item_count(), order.total());
}

Output:

Order 17: 2 items, 350 cents
Order 17: 3 items, 400 cents
▶ Try it Yourself

There’s a middle way you’ll see in many libraries: a private field plus a public method with the same name (a “getter”). Other code can read the value with acc.balance() but can’t change it directly. Writing acc.balance from outside the module then gives a slightly different error, E0616 “field balance of struct Account is private”, with the hint a method `balance` also exists, call it with parentheses. Same fix: add (). See Everything is private by default.

Habits from other languages. name.len, list.is_empty, text.trim, words.iter().count all give E0615. Every one of them is a method in Rust, so every one needs (). Fix: name.len(), list.is_empty(), and so on. See Useful string methods.

len on a Vec. scores.len is the one exception to the message: you get E0616, “field len of struct Vec is private”, because Vec really has a hidden field called len. rustc still adds help: a method `len` also exists, call it with parentheses. Fix: scores.len(). (scores.is_empty gives the normal E0615.) See Vectors.

A method that changes something. counter.increment; on its own line gives E0615 as well, even though you didn’t want a value. Without () nothing runs. Fix: counter.increment();.

The reverse: calling a field like a method. If name is a field, user.name() gives E0599 with the label field, not a method and help: remove the arguments. Fix: user.name. And if the field holds a closure, like on_click: Box<dyn Fn() -> String>, rustc says surround the field access with parentheses: write (button.on_click)() to call it.

Quick check

1. You get "attempted to take value of method is_empty on type String". What's the fix?

2. Which one should usually be a method instead of a stored field?

3. You want the length of every word: words.iter().map(???). What works?

Score: 0 / 3