Error Rust E0308: mismatched types (tipe tidak cocok)
E0308 artinya Rust mengharapkan nilai dengan satu tipe, tapi kamu memberinya nilai dengan tipe lain. Kemungkinan besar inilah error yang paling sering kamu temui di Rust. Untungnya, pesannya hampir selalu menyebutkan kedua tipe itu, jadi biasanya cepat diperbaiki. (Mencari error lain? Lihat Penjelasan error compiler Rust.)
Pesan error-nya
Section titled “Pesan error-nya”error[E0308]: mismatched types --> src/main.rs:6:29 |6 | let user = User { name: "Ferris" }; | ^^^^^^^^ expected `String`, found `&str` |help: try using a conversion method |6 | let user = User { name: "Ferris".to_string() }; | ++++++++++++Compiler bilang di baris 6 ia mengharapkan String tapi menemukan &str, lalu menyarankan konversi dengan .to_string().
Ini program yang menghasilkan error tersebut:
struct User { name: String,}
fn main() { let user = User { name: "Ferris" }; println!("{}", user.name);}Apa artinya
Section titled “Apa artinya”Setiap pesan E0308 punya bentuk yang sama: expected A, found B (diharapkan A, ditemukan B).
- Expected adalah tipe yang dibutuhkan Rust di posisi itu. Tipe ini datang dari tempat lain: anotasi tipe, tipe parameter atau tipe kembalian sebuah fungsi, field struct, atau cabang lain dari
if/match. - Found adalah tipe dari nilai yang benar-benar kamu tulis di situ.
Di contoh tadi, field name dideklarasikan sebagai String, jadi itulah yang diharapkan Rust. Tapi "Ferris" adalah string literal, dan tipenya &str. Keduanya berhubungan, tapi bukan tipe yang sama.
Perhatikan juga baris help:. Untuk E0308, compiler sering menyarankan perbaikan yang persis, seperti .to_string() di atas.
Kenapa Rust melakukan ini
Section titled “Kenapa Rust melakukan ini”Rust tidak pernah mengubah tipe diam-diam. Di beberapa bahasa, angka bisa berubah jadi string tanpa kamu sadari, atau angka besar dipotong supaya muat di tipe yang lebih kecil. Konversi tersembunyi seperti itu menimbulkan bug sungguhan: data hilang, hasil salah, atau crash yang terjadi jauh dari tempat kesalahan aslinya.
Karena itu Rust membuat setiap konversi terlihat di kode. Memang sedikit lebih banyak mengetik, tapi saat kamu membaca kodenya nanti, kamu bisa melihat persis di mana sebuah nilai berganti tipe dan apakah langkah itu bisa gagal. Tipe-tipenya sendiri dijelaskan di Tipe data.
Cara memperbaikinya
Section titled “Cara memperbaikinya”Setiap perbaikan di bawah dimulai dengan bentuk error-nya, jadi kamu bisa langsung lompat ke yang cocok dengan error-mu.
Perbaikan 1: Hapus titik koma di akhir
Section titled “Perbaikan 1: Hapus titik koma di akhir”error[E0308]: mismatched types --> src/main.rs:1:46 |1 | fn total_price(price: u32, quantity: u32) -> u32 { | ----------- ^^^ expected `u32`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression2 | price * quantity; | - help: remove this semicolon to return this valueKalau kamu melihat found (), periksa baris terakhir fungsinya. Di Rust, ekspresi terakhir sebuah blok yang tanpa titik koma adalah nilai kembaliannya. Menambahkan ; mengubahnya menjadi statement, sehingga fungsi itu mengembalikan () (tipe “kosong”). Compiler bahkan menunjuk titik komanya dan bilang “remove this semicolon” (hapus titik koma ini). Hapus saja:
fn total_price(price: u32, quantity: u32) -> u32 { price * quantity // tanpa titik koma: nilai ini yang dikembalikan}
fn main() { println!("Total: {}", total_price(250, 3));}Output:
Total: 750Hal yang sama terjadi di dalam blok if dan cabang match. Selengkapnya di Fungsi.
Perbaikan 2: Konversi antara String dan &str
Section titled “Perbaikan 2: Konversi antara String dan &str”String adalah string yang dimiliki (owned) dan bisa bertambah panjang. &str adalah tampilan pinjaman atas sebuah teks. Cerita lengkapnya ada di String. Konversinya pendek, ke dua arah:
&strkeString:.to_string()atauString::from(...).Stringke&str: pinjam dengan&(atau panggil.as_str()).
Kasus kedua muncul sebagai expected &str, found String, biasanya saat kamu memberikan String ke fungsi yang menerima &str.
struct User { name: String,}
fn greet(name: &str) { println!("Halo, {name}!");}
fn main() { // &str -> String: .to_string() atau String::from() let user = User { name: "Ferris".to_string() };
// String -> &str: pinjam dengan & (atau panggil .as_str()) greet(&user.name); greet(user.name.as_str());
let mut tags: Vec<String> = Vec::new(); tags.push(String::from("rust")); println!("{tags:?}");}Output:
Halo, Ferris!Halo, Ferris!["rust"]Perbaikan 3: Konversi antartipe angka
Section titled “Perbaikan 3: Konversi antartipe angka”error[E0308]: mismatched types --> src/main.rs:3:22 |3 | let count: i32 = names.len(); | --- ^^^^^^^^^^^ expected `i32`, found `usize` | | | expected due to thisDi sini anotasi i32 (ditunjuk dengan “expected due to this”) tidak cocok dengan usize yang dikembalikan .len(). i32, i64, u32, dan usize semuanya tipe yang berbeda, dan Rust tidak mau mencampurnya. Panjang dan indeks selalu bertipe usize. Pilih salah satu cara konversi:
.into()(ataui64::from(x)) kalau konversinya tidak mungkin kehilangan data, misalnyai32kei64.i64::try_from(x)(atau.try_into()) kalau nilainya mungkin tidak muat. HasilnyaResult, jadi kamu yang menentukan apa yang terjadi kalau gagal.asadalah cast cepat. Ia tidak pernah gagal, tapi diam-diam memotong nilai yang tidak muat, jadi pakai hanya kalau kamu yakin nilainya kecil.
fn average(total: i64, count: i64) -> i64 { total / count}
fn main() { let scores: Vec<i32> = vec![80, 95, 70]; let total: i32 = scores.iter().sum();
// i32 -> i64 selalu muat, jadi .into() sudah cukup let total: i64 = total.into();
// usize -> i64 mungkin tidak muat, jadi try_from bertanya dulu let count = i64::try_from(scores.len()).unwrap();
println!("Rata-rata: {}", average(total, count));
// `as` juga bisa, tapi diam-diam memotong nilai yang tidak muat let players = scores.len() as i32; println!("{players} pemain");}Output:
Rata-rata: 813 pemainSering kali perbaikan paling sederhana justru mengubah anotasinya: let count: usize = names.len();. Halaman Konversi tipe dan Konversi membahasnya lebih dalam.
Perbaikan 4: Bungkus dengan Some, atau buka Option-nya
Section titled “Perbaikan 4: Bungkus dengan Some, atau buka Option-nya”error[E0308]: mismatched types --> src/main.rs:3:27 |3 | let position: usize = names.iter().position(|n| *n == "Ben"); | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `Option<usize>` | | | expected due to thisOption<usize> bukan usize. Artinya “mungkin sebuah usize, mungkin tidak ada apa-apa”. Ketidakcocokan ini bisa terjadi ke dua arah:
- Expected
T, foundOption<T>: kamu harus menangani kasus “tidak ada apa-apa”, denganmatch,if let, atauunwrap_or(default). - Expected
Option<T>, foundT: fungsimu mengembalikanOption, jadi bungkus nilainya:Some(10), bukan10.
fn find_discount(code: &str) -> Option<u32> { if code == "SAVE10" { return Some(10); // T -> Option<T>: bungkus dengan Some } None}
fn main() { let names = vec!["Ana", "Ben", "Cy"];
// Option<T> -> T: tangani kasus "tidak ditemukan"... match names.iter().position(|n| *n == "Ben") { Some(i) => println!("Ben ada di posisi {i}"), None => println!("Ben tidak ada di sini"), }
// ...atau pilih nilai default dengan unwrap_or let discount: u32 = find_discount("HELLO").unwrap_or(0); println!("Diskon: {discount}%");}Output:
Ben ada di posisi 1Diskon: 0%Compiler mungkin menyarankan .expect("REASON"). Itu juga bisa, tapi program akan crash kalau nilainya None, jadi pakai hanya kalau None memang tidak mungkin terjadi. Lihat Option.
Perbaikan 5: Samakan tipe setiap cabang if/else dan match
Section titled “Perbaikan 5: Samakan tipe setiap cabang if/else dan match”error[E0308]: `if` and `else` have incompatible types --> src/main.rs:3:52 |3 | let label = if stock > 0 { "in stock" } else { stock }; | ---------- ^^^^^ expected `&str`, found integer | | | expected because of thisPesan ini berarti cabang if dan else menghasilkan tipe yang berbeda: yang satu &str, yang lain integer. Saat if atau match menghasilkan nilai, Rust perlu tahu satu tipe untuk nilai itu. Jadi setiap cabang harus menghasilkan tipe yang sama. Cabang pertama menentukan harapannya, dan error-nya menunjuk cabang yang tidak sepakat. Untuk match, pesannya berbunyi “match arms have incompatible types”. Samakan cabang yang berbeda itu:
fn status_text(code: u16) -> String { match code { 200 => "OK".to_string(), 404 => "Not Found".to_string(), _ => format!("Kode tidak dikenal {code}"), // setiap cabang adalah String }}
fn main() { let stock = 0; let label = if stock > 0 { "tersedia" } else { "habis" }; // keduanya &str println!("{label}");
println!("{}", status_text(404)); println!("{}", status_text(418));}Output:
habisNot FoundKode tidak dikenal 418Di sini satu cabang butuh format!, yang menghasilkan String, jadi cabang lainnya juga dijadikan String. Lihat If…Else dan Match.
Di mana biasanya kamu melihatnya
Section titled “Di mana biasanya kamu melihatnya”- Membaca input pengguna.
let age: u32 = input.trim();menghasilkan “expectedu32, found&str”. Teks bukan angka. Perbaikan: parse dulu:let age: u32 = input.trim().parse().unwrap();(atau tangani error-nya, lihat Result). - Memasukkan literal ke
Vec<String>.tags.push("rust")menghasilkan “expectedString, found&str”. Perbaikan:tags.push("rust".to_string()), atau jadikanVec<&str>kalau semua string-nya literal. - Hitungan dengan tipe angka campuran.
total + ndengantotalbertipei64dannbertipei32menghasilkan E0308 (dan sering E0277 di sebelahnya). Perbaikan: konversi salah satu sisi dulu:total + i64::from(n).
Error terkait
Section titled “Error terkait”- E0277: the trait bound is not satisfied (trait tidak terpenuhi). Sering muncul bersama E0308, misalnya saat kamu menjumlahkan
i64dengani32. - E0599: no method found (method tidak ditemukan). Kamu memanggil method yang tidak ada pada tipe ini, sering karena nilainya bertipe lain dari yang kamu kira.
- E0425: cannot find value in this scope (nama tidak dikenal). Sebuah nama yang sama sekali tidak dikenal Rust.
- Semua error compiler: daftar lengkap halaman error.
Kuis singkat
Section titled “Kuis singkat”Kuis singkat
1. Sebuah fungsi ditulis -> i32, tapi error-nya bilang "expected i32, found ()". Apa penyebab yang paling mungkin?
2. Sebuah fungsi menerima &str dan kamu punya let name = String::from("Ana");. Bagaimana cara memberikannya?
3. Konversi mana yang tidak mungkin diam-diam kehilangan data?
Skor: 0 / 3
Bacaan lebih lanjut
Section titled “Bacaan lebih lanjut”- E0308 — Rust error codes index (bahasa Inggris): penjelasan resmi error ini.
- Functions with Return Values — The Rust Book (bahasa Inggris): kenapa titik koma di akhir mengubah apa yang dikembalikan sebuah fungsi.
- Storing UTF-8 Text with Strings — The Rust Book (bahasa Inggris): hubungan
Stringdan&str, dan cara mengonversi di antara keduanya. - Conversion — Rust by Example (bahasa Inggris):
From,Into,TryFrom, danTryIntodengan contoh singkat. - Option — standard library Rust (bahasa Inggris): semua method untuk mengambil nilai dari
Option, sepertiunwrap_ordanmap.