Zum Inhalt springen

Rust-Fehler E0615: attempted to take value of method (Methode ohne Klammern)

E0615 bedeutet: Du hast value.something ohne Klammern geschrieben, aber something ist eine Methode und kein Feld. In Rust läuft eine Methode nur, wenn du sie mit () aufrufst – auch dann, wenn sie keine Argumente braucht. Dieser Fehler ist sehr häufig, wenn du von C#, JavaScript oder Python kommst. Dort sehen .Count, .length oder eine Property wie ganz normale Felder aus. Die Lösung ist fast immer zwei Zeichen lang. (Diese Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.)

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` ist eine Methode
| ^^^ method, not a field
|
help: use parentheses to call the method
|
3 | println!("{} has {} letters", name, name.len()); // ❌ `len` ist eine Methode
| ++

„Attempted to take value of method“ heißt so viel wie „Versuch, den Wert einer Methode zu nehmen“. Das help sagt: „Benutze Klammern, um die Methode aufzurufen.“

Dieses Programm erzeugt den Fehler:

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

Lies die Überschrift von hinten: on type String ist der Typ, den Rust sich angesehen hat, und method len ist das, was es dort gefunden hat. Rust hat len also gefunden. Es ist nur kein Wert, den du wie ein Feld lesen kannst. Es ist ein Stück Code, das erst laufen muss.

Genau das sagen die Markierung method, not a field (Methode, kein Feld) und die ++ unter () im help: Setz die Klammern, und du bist fertig.

Stell dir einen Getränkeautomaten vor. Ein Feld ist ein Schild, das auf den Automaten gedruckt ist („Automat Nr. 12“): Du liest es einfach ab. Eine Methode ist ein Knopf („Wechselgeld anzeigen“): Es passiert nichts, bis du ihn drückst. name.len zeigt auf den Knopf. name.len() drückt ihn.

Rust trennt Felder und Methoden streng. Ein Feld sind Daten, die im Struct gespeichert sind. Eine Methode ist eine Funktion in einem impl-Block, die self nimmt. Ein Feld liest du mit value.field, eine Methode rufst du mit value.method() auf. Siehe Verhalten mit Methoden hinzufügen.

Viele Sprachen verwischen diese Grenze mit Properties: list.Count in C# oder text.length in JavaScript sehen wie Felder aus, führen aber im Hintergrund Code aus. Rust hat absichtlich keine Properties. Siehst du (), weißt du: Hier läuft Code, und das kann Zeit kosten. Siehst du keine Klammern, ist es einfaches Lesen von gespeicherten Daten. Nichts ist versteckt.

Ein Struct kann sogar ein Feld und eine Methode mit demselben Namen haben, etwa ein privates Feld balance und eine öffentliche Methode balance(). Das geht nur, weil Rust nie rät, was du gemeint hast: ohne Klammern das Feld, mit Klammern die Methode.

Nimm diese Lösung fast immer. Folge der help:-Zeile und ruf die Methode auf. Das funktioniert für deine eigenen Methoden (wie total bei einem Warenkorb) genauso wie für Standardmethoden wie len, is_empty, trim und count:

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

Ausgabe:

Ferris hat 6 Buchstaben
Summe: 600 Cent
▶ Selbst ausprobieren

Braucht die Methode Argumente, zeigt rustc mit einem Platzhalter _, wo sie hingehören. Bei s.contains lautet das help s.contains(_): Setz ein, wonach du suchst, zum Beispiel s.contains("world"). Bist du nicht sicher, was eine Methode braucht, sagt dir der nächste Fehler von rustc (E0061), wie viele Argumente sie nimmt.

Lösung 2: Die Methode als Funktion übergeben, nicht value.method

Abschnitt betitelt „Lösung 2: Die Methode als Funktion übergeben, nicht value.method“

Nimm diese Lösung, wenn du die Methode gar nicht sofort aufrufen wolltest, sondern sie an etwas anderes weitergeben willst, etwa an .map() oder sort_by_key. Auch .map(words[0].len) ergibt E0615. Du hast zwei gute Möglichkeiten: ein kurzes Closure, das die Methode aufruft, oder den vollen Pfad der Methode, String::len, der wie ein Funktionsname funktioniert:

fn main() {
let words = vec![String::from("crab"), String::from("ferris"), String::from("rust")];
// ein Closure, das die Methode für jedes Element aufruft
let lengths: Vec<usize> = words.iter().map(|w| w.len()).collect();
println!("{:?}", lengths);
// der Pfad der Methode funktioniert wie ein Funktionsname
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);
}

Ausgabe:

[4, 6, 4]
[4, 6, 4]
["crab", "rust", "ferris"]
▶ Selbst ausprobieren

Die Wörter bleiben hier auf Englisch, weil die Ausgabe ihre Länge zeigt. String::len funktioniert, weil iter() dir &String-Elemente gibt und String::len ein &String nimmt. Passen die Typen nicht genau zusammen, ist das Closure |w| w.len() die einfache Wahl, die immer klappt.

Lösung 3: Ein Feld daraus machen, wenn es wirklich gespeicherte Daten sind

Abschnitt betitelt „Lösung 3: Ein Feld daraus machen, wenn es wirklich gespeicherte Daten sind“

Nimm diese Lösung, wenn der Fehler in deinem eigenen Struct steckt und du merkst, dass der Wert einfach gespeichert werden sollte. Das ist eine Designfrage: Feld oder Methode?

  • Mach ein Feld daraus, wenn der Wert einmal festgelegt wird und von nichts anderem abhängt: eine id, ein name, ein Datum created_at.
  • Mach eine Methode daraus, wenn der Wert aus anderen Daten berechnet wird: eine total aus den Artikeln, eine area aus Breite und Höhe, eine len aus dem Inhalt.

Ein gespeichertes Feld total wäre veraltet, sobald jemand einen Artikel hinzufügt und vergisst, es zu aktualisieren. Eine Methode total() wird jedes Mal neu berechnet, sie kann also nie falsch sein. Hier ist id ein Feld und total eine Methode, und du siehst, dass die Methode stimmt, auch wenn sich die Bestellung ändert:

mod shop {
pub struct Order {
pub id: u32, // gespeichert: einmal gesetzt, gelesen mit order.id
prices: Vec<u32>, // privat: wird nur über Methoden geändert
}
impl Order {
pub fn new(id: u32) -> Self {
Order { id, prices: Vec::new() }
}
pub fn add(&mut self, price: u32) {
self.prices.push(price);
}
// berechnet: passt immer zu den Preisen, kann nicht veralten
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!("Bestellung {}: {} Artikel, {} Cent", order.id, order.item_count(), order.total());
order.add(50);
println!("Bestellung {}: {} Artikel, {} Cent", order.id, order.item_count(), order.total());
}

Ausgabe:

Bestellung 17: 2 Artikel, 350 Cent
Bestellung 17: 3 Artikel, 400 Cent
▶ Selbst ausprobieren

Es gibt einen Mittelweg, den du in vielen Bibliotheken siehst: ein privates Feld plus eine öffentliche Methode mit demselben Namen (ein „Getter“). Anderer Code kann den Wert mit acc.balance() lesen, ihn aber nicht direkt ändern. Schreibst du acc.balance von außerhalb des Moduls, bekommst du einen etwas anderen Fehler: E0616 „field balance of struct Account is private“ (das Feld ist privat), mit dem Hinweis a method `balance` also exists, call it with parentheses (es gibt auch eine Methode balance, ruf sie mit Klammern auf). Die Lösung ist dieselbe: () ergänzen. Siehe Alles ist standardmäßig privat.

Gewohnheiten aus anderen Sprachen. name.len, list.is_empty, text.trim, words.iter().count ergeben alle E0615. Jede davon ist in Rust eine Methode, also braucht jede (). Lösung: name.len(), list.is_empty() und so weiter. Siehe Nützliche String-Methoden.

len bei einem Vec. scores.len ist die eine Ausnahme: Du bekommst E0616, „field len of struct Vec is private“ (das Feld len ist privat), weil Vec wirklich ein verstecktes Feld namens len hat. rustc ergänzt trotzdem help: a method `len` also exists, call it with parentheses. Lösung: scores.len(). (scores.is_empty ergibt das normale E0615.) Siehe Vektoren.

Eine Methode, die etwas ändert. Auch counter.increment; allein in einer Zeile ergibt E0615, obwohl du gar keinen Wert haben wolltest. Ohne () läuft nichts. Lösung: counter.increment();.

Andersherum: ein Feld wie eine Methode aufrufen. Ist name ein Feld, ergibt user.name() den Fehler E0599 mit der Markierung field, not a method (Feld, keine Methode) und help: remove the arguments (entferne die Argumente). Lösung: user.name. Und wenn das Feld ein Closure enthält, etwa on_click: Box<dyn Fn() -> String>, sagt rustc surround the field access with parentheses (setz den Feldzugriff in Klammern): Schreib (button.on_click)(), um es aufzurufen.

Kurzer Check

1. Du bekommst „attempted to take value of method is_empty on type String“. Was ist die Lösung?

2. Was sollte meistens eine Methode statt eines gespeicherten Felds sein?

3. Du willst die Länge jedes Worts: words.iter().map(???). Was funktioniert?

Punkte: 0 / 3