Lewati ke konten

Error Rust E0615: attempted to take value of method (method tanpa tanda kurung)

E0615 artinya: kamu menulis value.something tanpa tanda kurung, padahal something adalah method, bukan field. Di Rust, sebuah method baru berjalan kalau kamu memanggilnya dengan (), meskipun method itu tidak butuh argumen sama sekali. Error ini sangat sering muncul kalau kamu terbiasa dengan C#, JavaScript, atau Python, di mana .Count, .length, atau sebuah property terlihat seperti field biasa. Perbaikannya hampir selalu cuma dua karakter. (Halaman ini bagian dari Penjelasan error compiler Rust.)

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

Artinya: kamu mencoba mengambil nilai dari method len pada tipe String. Compiler menyarankan memakai tanda kurung untuk memanggil method-nya.

Ini program yang menghasilkan error tersebut:

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

Baca judul error-nya dari belakang: on type String adalah tipe yang diperiksa Rust, dan method len adalah yang ia temukan di sana. Jadi Rust berhasil menemukan len. Hanya saja, len bukan nilai yang bisa kamu baca seperti field. Ia adalah potongan kode yang harus dijalankan.

Label method, not a field (method, bukan field) dan tanda ++ di bawah () pada bagian help mengatakan persis hal itu: tambahkan tanda kurungnya, dan selesai.

Bayangkan sebuah mesin penjual otomatis. Field itu seperti label yang tercetak di mesinnya (“Mesin #12”): kamu tinggal membacanya. Method itu seperti tombol (“Tampilkan kembalian”): tidak terjadi apa-apa sampai kamu menekannya. name.len hanya menunjuk ke tombolnya. name.len() menekannya.

Rust memisahkan field dan method dengan tegas. Field adalah data yang disimpan di dalam struct. Method adalah fungsi yang didefinisikan di blok impl dan menerima self. Kamu membaca field dengan value.field dan memanggil method dengan value.method(). Lihat Menambahkan perilaku dengan method.

Banyak bahasa mengaburkan batas ini dengan property: list.Count di C# atau text.length di JavaScript terlihat seperti field, tapi sebenarnya menjalankan kode di belakang layar. Rust sengaja tidak punya property. Kalau kamu melihat (), kamu tahu ada kode yang berjalan dan mungkin butuh waktu. Kalau tidak ada, kamu tahu itu hanya membaca data yang tersimpan. Tidak ada yang disembunyikan.

Sebuah struct bahkan boleh punya field dan method dengan nama yang sama, misalnya field private balance dan method public balance(). Itu hanya mungkin karena Rust tidak pernah menebak mana yang kamu maksud: tanpa tanda kurung berarti field, dengan tanda kurung berarti method.

Pilih ini hampir setiap saat. Ikuti baris help: dan panggil method-nya. Caranya sama untuk method buatanmu sendiri (seperti total pada keranjang belanja) maupun method standar seperti len, is_empty, trim, dan count:

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

Output:

Ferris punya 6 huruf
Total: 600 sen
▶ Coba sendiri

Kalau method-nya butuh argumen, rustc menunjukkan tempatnya dengan placeholder _. Untuk s.contains, bagian help-nya berbunyi s.contains(_): isi dengan yang kamu cari, misalnya s.contains("world"). Kalau kamu tidak yakin apa yang dibutuhkan sebuah method, error rustc berikutnya (E0061) akan memberi tahu berapa argumen yang diterimanya.

Perbaikan 2: Berikan method-nya sebagai fungsi, bukan value.method

Section titled “Perbaikan 2: Berikan method-nya sebagai fungsi, bukan value.method”

Pilih ini kalau kamu tidak ingin memanggil method-nya sekarang, tapi ingin menyerahkannya ke hal lain, seperti .map() atau sort_by_key. Menulis .map(words[0].len) juga menghasilkan E0615. Ada dua pilihan yang bagus: sebuah closure pendek yang memanggil method-nya, atau path lengkap method itu, String::len, yang bisa dipakai seperti nama fungsi:

fn main() {
let words = vec![String::from("crab"), String::from("ferris"), String::from("rust")];
// closure yang memanggil method pada setiap item
let lengths: Vec<usize> = words.iter().map(|w| w.len()).collect();
println!("{:?}", lengths);
// path method-nya bisa dipakai seperti nama fungsi
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"]
▶ Coba sendiri

Kata-kata di contoh ini sengaja dibiarkan dalam bahasa Inggris, karena output-nya bergantung pada panjang setiap kata.

String::len bisa dipakai di sini karena iter() memberimu item bertipe &String, dan String::len menerima &String. Kalau tipenya tidak pas persis, closure |w| w.len() adalah pilihan mudah yang selalu berhasil.

Perbaikan 3: Jadikan field, kalau memang itu data yang disimpan

Section titled “Perbaikan 3: Jadikan field, kalau memang itu data yang disimpan”

Pilih ini kalau error-nya ada di struct buatanmu sendiri, dan kamu sadar nilainya sebaiknya disimpan saja. Ini pertanyaan desain: field atau method?

  • Jadikan field kalau nilainya diberikan sekali dan tidak bergantung pada hal lain: sebuah id, name, atau tanggal created_at.
  • Jadikan method kalau nilainya dihitung dari data lain: total dari item-itemnya, area dari lebar dan tinggi, len dari isinya.

Field total yang disimpan akan langsung basi begitu seseorang menambah item dan lupa memperbaruinya. Method total() dihitung ulang setiap kali dipanggil, jadi hasilnya tidak mungkin salah. Di sini id adalah field dan total adalah method, dan kamu bisa lihat method-nya tetap benar saat pesanannya berubah:

mod shop {
pub struct Order {
pub id: u32, // disimpan: diisi sekali, dibaca dengan order.id
prices: Vec<u32>, // private: hanya diubah lewat method
}
impl Order {
pub fn new(id: u32) -> Self {
Order { id, prices: Vec::new() }
}
pub fn add(&mut self, price: u32) {
self.prices.push(price);
}
// dihitung: selalu cocok dengan prices, tidak bisa basi
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!("Pesanan {}: {} item, {} sen", order.id, order.item_count(), order.total());
order.add(50);
println!("Pesanan {}: {} item, {} sen", order.id, order.item_count(), order.total());
}

Output:

Pesanan 17: 2 item, 350 sen
Pesanan 17: 3 item, 400 sen
▶ Coba sendiri

Ada jalan tengah yang sering kamu temui di banyak library: field private ditambah method public dengan nama yang sama (sebuah “getter”). Kode lain bisa membaca nilainya dengan acc.balance(), tapi tidak bisa mengubahnya langsung. Menulis acc.balance dari luar modul akan menghasilkan error yang sedikit berbeda, E0616 “field balance of struct Account is private” (field balance pada struct Account bersifat private), dengan petunjuk a method `balance` also exists, call it with parentheses (ada juga method balance, panggil dengan tanda kurung). Perbaikannya sama: tambahkan (). Lihat Semuanya private secara default.

Kebiasaan dari bahasa lain. name.len, list.is_empty, text.trim, words.iter().count semuanya menghasilkan E0615. Semuanya adalah method di Rust, jadi semuanya butuh (). Perbaikannya: name.len(), list.is_empty(), dan seterusnya. Lihat Method string yang berguna.

len pada Vec. scores.len adalah satu-satunya pengecualian: kamu mendapat E0616, “field len of struct Vec is private”, karena Vec memang punya field tersembunyi bernama len. rustc tetap menambahkan help: a method `len` also exists, call it with parentheses. Perbaikannya: scores.len(). (scores.is_empty menghasilkan E0615 yang biasa.) Lihat Vektor.

Method yang mengubah sesuatu. counter.increment; di barisnya sendiri juga menghasilkan E0615, padahal kamu tidak sedang butuh nilainya. Tanpa (), tidak ada yang dijalankan. Perbaikannya: counter.increment();.

Kebalikannya: memanggil field seperti method. Kalau name adalah field, user.name() menghasilkan E0599 dengan label field, not a method (field, bukan method) dan help: remove the arguments (hapus argumennya). Perbaikannya: user.name. Dan kalau field-nya berisi closure, seperti on_click: Box<dyn Fn() -> String>, rustc bilang surround the field access with parentheses (apit akses field-nya dengan tanda kurung): tulis (button.on_click)() untuk memanggilnya.

Kuis singkat

1. Kamu mendapat "attempted to take value of method is_empty on type String". Apa perbaikannya?

2. Mana yang biasanya lebih baik dijadikan method, bukan field yang disimpan?

3. Kamu ingin panjang setiap kata: words.iter().map(???). Mana yang berhasil?

Skor: 0 / 3