Lewati ke konten

Error Rust E0614: type cannot be dereferenced (tipe tidak bisa di-dereference)

E0614 artinya: kamu menulis * di depan sesuatu yang bukan referensi, jadi tidak ada yang bisa diikuti. Operator * berarti “pergi ke nilai yang ditunjuk referensi ini” (dereference). u32, i32, atau struct biasa tidak menunjuk ke mana pun: ia adalah nilainya. Ini biasanya terjadi di closure dan perulangan, tempat kamu gampang lupa apakah yang kamu pegang &u32 atau u32. rustc menyebut tipe sebenarnya di judul error-nya, dan perbaikannya hampir selalu menghapus satu *. (Halaman ini bagian dari Penjelasan error compiler Rust.)

error[E0614]: type `u32` cannot be dereferenced
--> src/main.rs:3:64
|
3 | let doubled: Vec<u32> = visits.iter().copied().map(|count| *count * 2).collect(); // ❌ `count` is already a `u32`
| ^^^^^^ can't be dereferenced

Artinya: tipe u32 tidak bisa di-dereference, dan tanda ^^^^^^ menunjuk ke *count.

Ini program yang menghasilkan error tersebut:

fn main() {
let visits: Vec<u32> = vec![12, 0, 7, 30];
let doubled: Vec<u32> = visits.iter().copied().map(|count| *count * 2).collect(); // ❌ `count` is already a `u32`
println!("{:?}", doubled);
}

Tanda ^^^^^^ menunjuk ke *count di baris 3, dengan label “can’t be dereferenced” (tidak bisa di-dereference). Judulnya memberi tahu apa sebenarnya count: sebuah u32, bukan &u32.

Ikuti tipenya di sepanjang rantai:

  1. visits.iter() memberimu referensi ke setiap item: &u32, &u32, …
  2. .copied() mengubah setiap &u32 menjadi salinan u32 biasa. Referensinya sudah hilang.
  3. Jadi di .map(|count| ...), count adalah u32, dan *count meminta Rust mengikuti pointer yang tidak ada.

Kalau judulnya bilang type `{integer}` cannot be dereferenced, artinya sama. {integer} adalah cara rustc menulis “suatu tipe integer yang belum aku tentukan”, biasanya angka seperti 72 yang tidak pernah kamu beri tipe.

Ibaratnya kamu bertanya ke seseorang “apa yang ada di alamat ini?”, tapi yang kamu serahkan paketnya, bukan secarik kertas berisi alamat. Barangnya sudah ada di tangan mereka; tidak ada alamat yang perlu didatangi.

Di Rust, referensi (&T) dan nilainya sendiri (T) adalah tipe yang berbeda. * hanya bekerja pada hal yang menunjuk ke suatu tempat: referensi &T dan &mut T, smart pointer seperti Box<T> dan Rc<T>, dan tipe apa pun yang mengimplementasikan trait Deref. u32 atau struct biasa tidak punya semua itu, jadi * padanya tidak ada artinya.

Rust bisa saja diam-diam mengabaikan * yang berlebih, tapi tidak. * yang berlebih biasanya berarti kamu keliru tentang tipe yang kamu pegang, dan kebingungan itu cenderung memicu bug lain: membandingkan hal yang salah, atau memindahkan (move) nilai yang seharusnya kamu pinjam. Jadi rustc berhenti dan memberi tahu tipe yang sebenarnya. Lihat Borrowing dan Smart Pointer.

Kesalahan kebalikannya punya error sendiri. Kalau kamu lupa sebuah * pada referensi, seperti count > 10 dengan count berupa &u32, kamu mendapat E0308 mismatched types (tipe tidak cocok).

Pilih ini hampir setiap saat, terutama setelah .copied(), .cloned(), .into_iter() pada Vec, atau apa pun yang memberimu nilai. Nilainya sudah ada, jadi langsung pakai saja:

fn main() {
let visits: Vec<u32> = vec![12, 0, 7, 30];
let doubled: Vec<u32> = visits.iter().copied().map(|count| count * 2).collect();
println!("{:?}", doubled);
// `filter` meminjamkan setiap item ke closure, jadi di sini `count` MEMANG `&u32`
// dan `*`-nya benar.
let busy: Vec<u32> = visits.iter().copied().filter(|count| *count > 10).collect();
println!("{:?}", busy);
}

Output:

[24, 0, 14, 60]
[12, 30]
▶ Coba sendiri

Bagian kedua itu sering menjebak: di rantai yang sama, map mendapat item-nya sendiri, sedangkan filter mendapat referensi ke item itu. Kalau ragu, lihat method-nya di dokumentasi. filter menerima FnMut(&Self::Item) -> bool, dengan &. Lihat Iterator dan Closure.

Perbaikan 2: Di for loop, pilih nilai atau referensi

Section titled “Perbaikan 2: Di for loop, pilih nilai atau referensi”

Pilih ini kalau *-nya ada di dalam for loop. for score in scores membongkar Vec-nya dan memberimu setiap nilai, jadi *score gagal:

error[E0614]: type `{integer}` cannot be dereferenced
--> src/main.rs:5:18
|
5 | total += *score; // ❌ `score` is a number, not a reference
| ^^^^^^ can't be dereferenced

Artinya: score adalah sebuah integer, dan integer tidak bisa di-dereference. Program yang rusak:

fn main() {
let scores = vec![72, 95, 88];
let mut total = 0;
for score in scores {
total += *score; // ❌ `score` is a number, not a reference
}
println!("total: {}", total);
}

Hapus *-nya, atau lakukan perulangan atas &scores. Dengan begitu setiap score adalah &i32, *-nya benar, dan kamu masih bisa memakai Vec-nya setelah perulangan:

fn main() {
let scores = vec![72, 95, 88];
let mut total = 0;
for score in &scores {
total += *score; // `score` sekarang `&i32`
}
println!("total: {}", total);
// `scores` tidak di-move ke dalam perulangan, jadi masih ada.
println!("{} skor, rata-rata {}", scores.len(), total / scores.len() as i32);
}

Output:

total: 255
3 skor, rata-rata 85
▶ Coba sendiri

Aturan singkatnya: for x in v memberi nilai, for x in &v memberi referensi &, for x in &mut v memberi referensi &mut. Hanya dua yang terakhir yang butuh *. Lihat Perulangan for dan Vektor.

Perbaikan 3: Cocokkan referensinya dengan &x, atau pakai *x, tapi jangan keduanya

Section titled “Perbaikan 3: Cocokkan referensinya dengan &x, atau pakai *x, tapi jangan keduanya”

Pilih ini kalau closure atau perulanganmu sudah punya & di pattern-nya, seperti |&p|. & di dalam pattern sudah membongkar referensinya untukmu, jadi p adalah angka biasa dan *p kelebihan satu langkah:

error[E0614]: type `{integer}` cannot be dereferenced
--> src/main.rs:3:53
|
3 | let with_fee: Vec<i32> = prices.iter().map(|&p| *p + 1).collect(); // ❌ `&p` already removed the `&`
| ^^ can't be dereferenced

Artinya: p sudah berupa integer, jadi *p tidak bisa di-dereference. Program yang rusak:

fn main() {
let prices = [3, 5, 8];
let with_fee: Vec<i32> = prices.iter().map(|&p| *p + 1).collect(); // ❌ `&p` already removed the `&`
println!("{:?}", with_fee);
}

Pilih satu cara untuk menyingkirkan referensinya. Kedua baris di bawah ini melakukan hal yang sama:

fn main() {
let prices = [3, 5, 8];
let with_fee: Vec<i32> = prices.iter().map(|&p| p + 1).collect(); // pattern menghapus `&`
let same: Vec<i32> = prices.iter().map(|p| *p + 1).collect(); // `*` menghapus `&`
println!("{:?} {:?}", with_fee, same);
// `filter` pada `.iter()` mendapat `&&i32`: dua `&`, jadi pattern-nya `&&p`.
let pricey = prices.iter().filter(|&&p| p > 4).count();
println!("{} barang mahal", pricey);
}

Output:

[4, 6, 9] [4, 6, 9]
2 barang mahal
▶ Coba sendiri

Hal yang sama berlaku untuk perulangan: for &(name, qty) in &orders membongkar setiap referensi, jadi pakai name dan qty tanpa *. Lihat Pattern Matching.

Perbaikan 4: Cek tipenya, lalu pakai field atau Deref untuk wrapper

Section titled “Perbaikan 4: Cek tipenya, lalu pakai field atau Deref untuk wrapper”

Pilih ini kalau judulnya menyebut tipe buatanmu sendiri, seperti type `Meters` cannot be dereferenced. Struct juga bukan referensi, bahkan kalau isinya cuma satu nilai:

error[E0614]: type `Meters` cannot be dereferenced
--> src/main.rs:5:18
|
5 | let longer = *run + 1.0; // ❌ `run` is a `Meters`, not a reference
| ^^^^ can't be dereferenced

Artinya: run bertipe Meters, bukan referensi, jadi *run tidak bisa di-dereference. Program yang rusak:

struct Meters(f64);
fn main() {
let run = Meters(2.5);
let longer = *run + 1.0; // ❌ `run` is a `Meters`, not a reference
println!("{} m", longer);
}

Untuk mengambil angka di dalam struct tuple, pakai field-nya, .0:

struct Meters(f64);
fn main() {
let run = Meters(2.5);
let longer = run.0 + 1.0;
println!("{} m", longer);
}

Output:

3.5 m
▶ Coba sendiri

Kalau tipemu memang wrapper yang mirip smart pointer dan kamu ingin * bisa dipakai, implementasikan std::ops::Deref untuknya. Lakukan itu hanya untuk tipe wrapper; untuk “newtype” seperti Meters, .0 atau sebuah method lebih jelas. Tidak yakin apa tipe sebuah variabel? Arahkan kursor ke variabel itu di editormu (rust-analyzer menampilkan tipenya), atau percayai judul error-nya: ia selalu menyebut tipe yang sebenarnya. Lihat Struct dan Smart Pointer.

* pada field struct. *config.retries, dengan config sebuah struct (atau referensi ke struct) dan retries sebuah u32, memberi type `u32` cannot be dereferenced. Tanda . sudah mengikuti referensinya untukmu. Perbaikannya: config.retries.

Perulangan atas HashMap berdasarkan nilai. for (word, count) in counts { total += *count; } memberi type `u32` cannot be dereferenced, karena perulangan atas counts itu sendiri memberi key dan value yang dimiliki (owned). Perbaikannya: hapus *-nya, atau lakukan perulangan atas &counts kalau kamu masih butuh map-nya sesudahnya. Lihat HashMap.

Setelah .copied().max() atau .cloned().find(...). Keduanya memberi Option<u32>, bukan Option<&u32>, jadi di if let Some(best) = ... { *best } tanda *-nya kelebihan satu. Perbaikannya: langsung pakai best. Tanpa .copied(), .iter().max() memberi Option<&u32> dan *best memang benar.

  • E0308: mismatched types; kesalahan kebalikannya, * yang terlupa saat referensi bertemu nilai biasa.
  • E0369: operasi biner tidak bisa diterapkan pada sebuah tipe, error lain yang bisa muncul saat referensi dan nilai bercampur.
  • E0507: cannot move out of a reference; di sini * memang bekerja, tapi akan memindahkan nilai yang bukan Copy.
  • E0610: {integer} adalah tipe primitif dan tidak punya field, saudara “ini cuma angka” dari error ini.
  • E0599: no method found, saat nilainya bukan tipe yang kamu kira.
  • Semua error compiler: daftar lengkap halaman error.

Kuis singkat

1. Di visits.iter().copied().map(|count| *count + 1), kenapa *count memberi E0614?

2. for score in &scores { total += *score; } dengan scores sebuah Vec<i32>. Apakah bisa ter-compile?

3. prices.iter().map(|&p| *p * 2) memberi E0614. Versi mana yang benar?

Skor: 0 / 3