Error Rust E0282: type annotations needed (anotasi tipe diperlukan)
E0282 artinya Rust sudah mencoba mencari tahu sebuah tipe sendiri, tapi tidak menemukan cukup petunjuk. Logikamu tidak salah. Compiler hanya butuh kamu menyebutkan satu tipe, biasanya dengan beberapa karakter tambahan saja. Halaman ini menunjukkan perbaikannya dulu, lalu menjelaskan cara Rust menebak tipe (namanya type inference, inferensi tipe), supaya kamu tahu kapan perlu membantunya. Untuk error lain di seri ini, lihat Penjelasan error compiler Rust.
Pesan error-nya
Section titled “Pesan error-nya”error[E0282]: type annotations needed for `Vec<_>` --> src/main.rs:2:9 |2 | let mut scores = Vec::new(); // sebuah Vec berisi... apa? | ^^^^^^^^^^ ---------- type must be known at this point |help: consider giving `scores` an explicit type, where the type for type parameter `T` is specified |2 | let mut scores: Vec<T> = Vec::new(); // sebuah Vec berisi... apa? | ++++++++Compiler bilang ia butuh anotasi tipe untuk Vec<_> ini, dan menyarankan kamu memberi scores tipe yang jelas.
Ini program yang menghasilkan error tersebut:
fn main() { let mut scores = Vec::new(); // sebuah Vec berisi... apa? println!("Scores recorded: {}", scores.len());}Pesan sama, kode berbeda
Section titled “Pesan sama, kode berbeda”Kata-kata “type annotations needed” juga muncul dengan tiga kode lain. Artinya sama, dan perbaikan di halaman ini berlaku untuk semuanya:
- E0283:
.collect()atau.sum()tanpa tipe tujuan. rustc menambahkan catatan sepertithe type must implement `FromIterator<&str>`atau`Sum<&i32>`, karena banyak tipe yang bisa jadi hasilnya. - E0284:
"42".parse().unwrap()tanpa tipe tujuan. Catatannya berbunyicannot satisfy `<_ as FromStr>::Err == _`, cara yang menyeramkan untuk bilang “di-parse menjadi apa?”. - E0790:
let settings = Default::default();. Judulnya berbunyicannot call associated function on trait without specifying the corresponding `impl` type: Rust tidak tahu default milik siapa yang kamu mau.
Kode mana yang kamu dapat bergantung pada baris persisnya, dan bisa berubah kalau kamu menambahkan kode lain. Misalnya, let age = "42".parse().unwrap(); menghasilkan E0284, tapi kalau baris berikutnya memanggil age.pow(2), error-nya menjadi E0282. Tidak usah pusing soal nomornya; lihat variabel yang ditunjuk rustc.
Apa artinya
Section titled “Apa artinya”Perhatikan dua tanda di bawah baris 2:
^^^^^^^^^^di bawahmut scores: inilah variabel yang tipenya tidak bisa ditebak Rust.----------di bawahVec::new(): “type must be known at this point” (tipenya harus sudah diketahui di titik ini).Vec::new()membuat daftar kosong, tapi daftar kosong berisi apa? Angka? Nama? Rust perlu tahu supaya bisa menyiapkan tempat penyimpanan yang tepat.- Bagian help menyarankan
let mut scores: Vec<T>. Di siniThanya placeholder. Kamu menggantinya dengan tipe sungguhan, sepertiVec<u32>.
Bayangkan sebuah paket di kantor pos dengan kolom “isi paket” yang dibiarkan kosong. Petugasnya tidak bisa mengirimnya sampai ada yang menulis sesuatu di situ. Kamu bisa menulisnya sendiri, atau memasukkan sesuatu ke dalam paket supaya petugasnya bisa melihat.
Kenapa Rust melakukan ini
Section titled “Kenapa Rust melakukan ini”Setiap nilai di Rust punya satu tipe yang pasti, yang ditentukan saat kompilasi. Biasanya kamu tidak perlu menuliskannya, karena Rust membaca kodemu dan menyimpulkannya sendiri. let count = 5; adalah i32. let name = String::from("Ferris"); adalah String. Itulah type inference, dan pelajaran Variabel menunjukkan lebih banyak contohnya.
Inference memakai petunjuk dari seluruh fungsi, bukan hanya satu baris. Kalau nanti kamu memanggil scores.push(90), itu petunjuk: Vec-nya berisi angka. Kalau kamu memberikan scores ke fungsi yang menerima &[u32], itu petunjuk yang lebih baik lagi. E0282 muncul kalau tidak ada petunjuk sama sekali, atau kalau Rust butuh tipenya sebelum sampai ke petunjuk itu (misalnya untuk mencari sebuah method).
Beberapa fungsi bersifat generik pada tipe kembaliannya: parse, collect, sum, Default::default, Vec::new, None. Fungsi-fungsi ini bisa menghasilkan banyak tipe berbeda, jadi Rust tidak bisa memilihkan satu untukmu. Rust tidak mau menebak, karena tebakan yang salah akan diam-diam mengubah perilaku programmu. Lihat Generics untuk tahu bagaimana satu fungsi bisa mengembalikan banyak tipe.
Cara memperbaikinya
Section titled “Cara memperbaikinya”Perbaikan 1: Beri anotasi pada variabelnya
Section titled “Perbaikan 1: Beri anotasi pada variabelnya”Pilih ini di kebanyakan kasus. Tambahkan : Tipe setelah nama variabelnya. Singkat, dan sekaligus menjadi dokumentasi untuk orang berikutnya yang membaca kodemu:
fn main() { let scores: Vec<u32> = Vec::new(); let age: u32 = "42".parse().unwrap(); let words: Vec<&str> = "merah hijau biru".split(' ').collect(); let winner: Option<String> = None;
println!("Skor tercatat: {}", scores.len()); println!("Tahun depan umurmu {}", age + 1); println!("{:?}", words); println!("{:?}", winner);}Output:
Skor tercatat: 0Tahun depan umurmu 43["merah", "hijau", "biru"]NoneKamu tidak selalu harus menulis tipenya lengkap. let words: Vec<_> = ...collect(); artinya “sebuah Vec, dan isinya silakan kamu tebak sendiri”. Tanda _ meminta Rust mengisi bagian itu. Selengkapnya tentang menulis tipe di Tipe data.
Perbaikan 2: Pakai turbofish ::<>
Section titled “Perbaikan 2: Pakai turbofish ::<>”Pilih ini kalau tidak ada variabel yang bisa diberi anotasi, misalnya di tengah rangkaian pemanggilan iterator. Kamu menaruh tipenya langsung di pemanggilan fungsi dengan ::<Tipe>. Orang menyebut ::<> “turbofish” karena bentuknya sedikit mirip ikan:
fn main() { let input = "4 15 7"; let numbers = input .split(' ') .map(|s| s.parse::<u32>().unwrap()) .collect::<Vec<_>>(); let total = numbers.iter().sum::<u32>();
println!("{:?}", numbers); println!("Total: {total}");}Output:
[4, 15, 7]Total: 26Tiga pemanggilan turbofish yang paling sering adalah parse::<i32>(), collect::<Vec<_>>(), dan sum::<i32>(). Perbaikan 1 dan Perbaikan 2 sama-sama benar; let total: u32 = numbers.iter().sum(); melakukan hal yang sama. Pilih yang menurutmu lebih enak dibaca.
Perbaikan 3: Pakai nilainya, supaya Rust bisa menebak tipenya
Section titled “Perbaikan 3: Pakai nilainya, supaya Rust bisa menebak tipenya”Pilih ini kalau error-nya muncul karena kodemu belum selesai. Sering kali kamu membuat Vec kosong, dan kode yang mengisinya baru ditulis belakangan. Begitu nilainya dipakai, Rust mendapat petunjuknya dan error-nya hilang, tanpa perlu anotasi:
fn print_team(names: &[String]) { for name in names { println!("- {name}"); }}
fn main() { let mut team = Vec::new(); // tipenya belum diketahui... untuk sementara team.push(String::from("Ferris")); // sekarang Rust tahu: Vec<String> team.push(String::from("Corro")); print_team(&team);}Output:
- Ferris- CorroUrutan sedikit berpengaruh. Petunjuknya harus muncul sebelum Rust butuh tipenya untuk memanggil sebuah method. Closure seperti let shout = |s| s.to_uppercase(); tetap gagal meskipun kamu memanggil shout("hi") di baris berikutnya, karena Rust harus tahu apa itu s untuk menemukan .to_uppercase(). Di situ, tulis tipenya: |s: &str| s.to_uppercase(). Lihat Closure.
Perbaikan 4: Sebutkan tipe untuk None dan Default::default()
Section titled “Perbaikan 4: Sebutkan tipe untuk None dan Default::default()”Pilih ini untuk nilai yang sama sekali tidak membawa petunjuk. None tidak bilang apa yang akan ia simpan, dan Default::default() tidak bilang default milik siapa yang kamu mau. Tuliskan tipenya di dalam ekspresi:
#[derive(Debug, Default)]struct Settings { volume: u8, muted: bool,}
fn main() { let fastest_lap = None::<f64>; // bukan: None let settings = Settings::default(); // bukan: Default::default() let backup: Settings = Default::default(); // anotasi juga bisa
println!("{:?}", fastest_lap); println!("{:?}", settings); println!("Volume cadangan: {}", backup.volume);}Output:
NoneSettings { volume: 0, muted: false }Volume cadangan: 0Settings::default() adalah pilihan paling jelas: terbaca sebagai “Settings default”. None::<f64> praktis, tapi let fastest_lap: Option<f64> = None; (Perbaikan 1) lebih umum dipakai. Lihat Option.
Di mana biasanya kamu melihatnya
Section titled “Di mana biasanya kamu melihatnya”Mem-parse teks menjadi angka. let guess = line.trim().parse().unwrap(); menghasilkan E0284 (atau E0282 kalau kamu memanggil method pada guess sesudahnya). parse bisa menghasilkan i32, u8, f64, dan banyak lagi. Perbaikannya: let guess: i32 = ... atau .parse::<i32>(). Membandingkan guess dengan variabel i32 belakangan tidak cukup di sini, karena parse butuh tipenya tepat saat dipanggil.
.collect(). Method ini bisa membangun Vec, String, HashSet, HashMap… jadi ia selalu perlu tahu tujuannya. Perbaikannya: let words: Vec<_> = ...collect(); atau .collect::<Vec<_>>(). Lihat Iterator.
.sum() dan .product(). nums.iter().sum() menghasilkan E0283 dengan the type must implement `Sum<&i32>`. Menjumlahkan i32 bisa menghasilkan i32, tapi tipe angka lain juga bisa jadi hasilnya. Perbaikannya: let total: i32 = nums.iter().sum(); atau .sum::<i32>().
Koleksi kosong di constructor struct. let cache = HashMap::new(); di dalam fungsi new() yang belum selesai kamu tulis. Perbaikannya: tulis tipe lengkapnya sekali (HashMap<String, u32>), atau kembalikan di dalam struct yang tipe field-nya sudah dideklarasikan, karena itu petunjuk yang bisa dipakai Rust.
Error terkait
Section titled “Error terkait”- E0308: mismatched types (tipe tidak cocok). Terjadi kalau anotasimu dan nilainya tidak sepakat, seperti
let age: u32 = "42";. - E0277: the trait bound is not satisfied (trait tidak terpenuhi). Kamu sudah memberi tipe, tapi tipe itu tidak bisa dibangun dengan cara tersebut, seperti
let n: Vec<i32> = "1 2".split(' ').collect();(ituVec<&str>; parse setiap item dulu). - E0599: no method found (method tidak ditemukan), misalnya saat kamu memberi anotasi
let n: u32lalu memanggil methodStringseperti.trim()padanya. - E0004: non-exhaustive patterns (pola belum lengkap), error lain yang perbaikannya dituliskan langsung oleh rustc.
- Semua error compiler: daftar lengkap halaman error.
Kuis singkat
Section titled “Kuis singkat”Kuis singkat
1. Baris mana yang memperbaiki E0282 pada let ids = Vec::new(); kalau Vec itu dimaksudkan berisi nilai u64?
2. Kenapa let n = "7".parse().unwrap(); butuh tipe, padahal teksnya jelas-jelas angka?
3. Apa arti _ di .collect::<Vec<_>>()?
Skor: 0 / 3
Bacaan lebih lanjut
Section titled “Bacaan lebih lanjut”- E0282 — Rust error codes index (bahasa Inggris): penjelasan resmi error ini, dengan contoh tambahan.
- E0283 — Rust error codes index (bahasa Inggris): varian yang akan kamu lihat dengan
collectdansum, saat banyak tipe bisa cocok. - Data Types — The Rust Book (bahasa Inggris): menjelaskan anotasi tipe, termasuk contoh klasik
"42".parse(). - Inference — Rust by Example (bahasa Inggris): contoh singkat Rust menebak tipe sebuah
Vecdari kode sesudahnya. Iterator::collect— dokumentasi standard library (bahasa Inggris): menunjukkan gaya anotasi dan gaya turbofish.