Lewati ke konten

Error Rust E0610: primitive type doesn't have fields (field pada angka)

E0610 artinya: kamu menulis something.field, padahal something adalah angka biasa (atau bool atau char), dan tipe-tipe itu sama sekali tidak punya field. Hampir selalu ini berarti variabelnya bukan seperti yang kamu kira. Mungkin kamu sudah mengambil angkanya keluar dari struct, sebuah fungsi mengembalikan angka dan bukan struct, atau kamu menulis satu .0 terlalu banyak. Pesan error-nya menyebutkan tipe persis yang dilihat Rust, jadi kamu tinggal selangkah lagi dari perbaikannya. (Halaman ini bagian dari Penjelasan error compiler Rust.)

error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
--> src/main.rs:3:22
|
3 | println!("{}", x.value); // ❌ x adalah angka, ia tidak punya field `value`
| ^^^^^

Artinya: {integer} adalah tipe primitif, jadi ia tidak punya field.

Ini program yang menghasilkan error tersebut:

fn main() {
let x = 5;
println!("{}", x.value); // ❌ x adalah angka, ia tidak punya field `value`
}

Tipe di dalam backtick adalah tipe yang menurut Rust dimiliki variabelmu. Di sini tipenya `{integer}`, yang artinya “suatu bilangan bulat, tapi aku belum memutuskan jenis yang mana” (Rust memilih i32 belakangan kalau tidak ada hal lain yang menentukan). Kamu juga bisa melihat `{float}` untuk bilangan desimal, atau tipe yang sudah pasti seperti u32, usize, f64, bool, atau char.

Tanda ^^^^^ menunjuk ke nama setelah titik. Rust tidak sedang bilang “ejaan value salah”. Rust bilang “angka tidak bisa punya field apa pun, apa pun namanya”.

Jadi pertanyaan yang perlu kamu ajukan adalah: kenapa variabel ini berupa angka? Ini seperti menanyakan “label harga dari angka 5”. Sebuah produk punya label harga. Angka 5 hanyalah angka.

Tipe primitif seperti i32, u32, f64, bool, dan char adalah nilai tunggal yang sudah tertanam di bahasa Rust. Mereka bukan struct, jadi tidak ada apa pun di dalamnya yang bisa dicapai dengan titik dan sebuah nama. Lihat Tipe data.

Tapi mereka punya method: x.abs(), x.pow(2), price.round(), c.is_alphabetic(). Method dipanggil dengan (). Field adalah data yang disimpan di dalam struct, dan hanya struct, tuple, dan union yang memilikinya.

Karena Rust memeriksa setiap .field saat kompilasi, salah paham seperti ini tidak akan pernah menjadi crash atau undefined diam-diam saat program berjalan. Kamu langsung tahu, tepat di baris yang salah.

Pilih ini kalau sebelumnya kamu sudah mengambil field-nya keluar dari struct. Setelah let count = counter.value;, count adalah angkanya, jadi count.value meminta field pada sebuah u32:

error[E0610]: `u32` is a primitive type and therefore doesn't have fields
--> src/main.rs:8:26
|
8 | println!("{}", count.value);
| ^^^^^

Pakai angkanya apa adanya, atau kembali ke struct-nya dan baca field dari sana:

struct Counter {
value: u32,
}
fn main() {
let mut counter = Counter { value: 0 };
counter.value += 3;
let count = counter.value; // sekarang count adalah u32 biasa
println!("{}", count); // ✅ pakai angkanya langsung
println!("{}", counter.value); // ✅ atau baca field dari struct-nya
}

Output:

3
3
▶ Coba sendiri

Tidak yakin apa tipe sebuah variabel? Arahkan kursor ke variabel itu di editor-mu (dengan rust-analyzer, lihat Tools dan setup Rust). Atau tulis let _: () = count; sebentar: rustc akan menjawab dengan expected `()`, found `usize` dan memberi tahu tipe sebenarnya. Hapus baris itu sesudahnya.

Perbaikan 2: Kembalikan atau simpan struct-nya, bukan angkanya

Section titled “Perbaikan 2: Kembalikan atau simpan struct-nya, bukan angkanya”

Pilih ini kalau nilainya berasal dari sebuah fungsi atau koleksi, dan kamu mengira itu struct. Dua kasus yang sering terjadi:

  • Fungsi seperti fn find_order() -> u32 mengembalikan id pesanan, lalu order.total gagal karena order adalah u32.
  • Sebuah HashMap<&str, u32> hanya menyimpan skor, lalu scores["ana"].score gagal karena setiap nilainya adalah u32, bukan Player.

Tentukan apa yang sebenarnya kamu butuhkan. Kalau kamu butuh beberapa data sekaligus, ubah tipe kembalian atau tipe nilainya menjadi struct:

use std::collections::HashMap;
struct Order {
id: u32,
total: u32, // dalam sen
}
// mengembalikan Order utuh, bukan cuma angka
fn new_order(id: u32, total: u32) -> Order {
Order { id, total }
}
struct Player {
score: u32,
level: u8,
}
fn main() {
let order = new_order(7, 1999);
println!("Pesanan {} harganya {} sen", order.id, order.total);
// map-nya menyimpan Player utuh, bukan cuma skornya
let mut players: HashMap<&str, Player> = HashMap::new();
players.insert("ana", Player { score: 10, level: 2 });
let ana = &players["ana"];
println!("ana: skor {}, level {}", ana.score, ana.level);
}

Output:

Pesanan 7 harganya 1999 sen
ana: skor 10, level 2
▶ Coba sendiri

Kalau kamu memang hanya butuh angka, biarkan tetap u32 dan cukup hapus bagian .field-nya. Lihat Struct dan HashMap.

Pilih ini kalau error-nya menunjuk ke .0 atau .1. Tuple dan tuple struct memakai posisi untuk field-nya, dan gampang sekali masuk satu tingkat terlalu dalam. Setelah let x = point.0;, x sudah berupa angka, jadi x.0 menghasilkan `{integer}` is a primitive type. Hal yang sama terjadi dengan pembungkus seperti struct Meters(u32);: satu .0 mengeluarkan u32-nya, dan .0 kedua gagal.

struct Meters(u32);
fn main() {
let point = (3, 4);
let x = point.0; // x sudah berupa angka 3
println!("x = {}", x); // bukan x.0
let m = Meters(42);
println!("{} m", m.0); // satu .0 mengeluarkan u32 dari tuple struct
let line = ((0, 0), (3, 4)); // tuple bersarang: satu posisi per tingkat
println!("y ujung = {}", line.1.1);
}

Output:

x = 3
42 m
y ujung = 4
▶ Coba sendiri

Hitung tingkatnya: setiap .0 atau .1 masuk satu tingkat ke dalam tuple. Begitu sampai di angka, berhenti. Kalau posisinya mulai membingungkan, beri nama dengan struct saja. Lihat Mengakses elemen berdasarkan posisi dan Kapan memakai tuple dan kapan memakai struct.

Method tanpa (). price.round pada f64, atau x.abs pada i32, bukan E0610 melainkan E0615, “attempted to take value of method”, karena nama-nama itu memang method. Perbaikannya: price.round(), x.abs(). Ada satu kejutan: kalau tipenya masih {integer} (seperti pada let x = -5;), bahkan x.abs pun menghasilkan E0610, lalu x.abs() menghasilkan E0689 “can’t call method abs on ambiguous numeric type {integer}” (tidak bisa memanggil method pada tipe angka yang ambigu). Pilih sebuah tipe, let x: i32 = -5;, dan x.abs() pun berhasil.

Referensi ke angka. Kalau variabelnya &u32, bukan u32, kodenya berubah menjadi E0609: no field `value` on type `&u32`. Tempat yang sering terjadi adalah loop seperti for (name, score) in &players, di mana score bertipe &i32, dan score.1 menghasilkan no field `1` on type `&{integer}`. Penyebabnya sama, perbaikannya juga sama: score sudah berupa angkanya.

Hasil dari len() atau count(). let len = scores.len(); memberimu sebuah usize, jadi len.count gagal dengan `usize` is a primitive type. Perbaikannya: pakai len langsung.

Angka dengan satuan. Kalau kamu ingin price.cents atau distance.meters, buat struct kecil: struct Price { cents: u64 }. Dengan begitu price.cents berhasil, dan tipenya mencegahmu tertukar antara harga dan angka lain. Lihat Struct.

Kuis singkat

1. Setelah let total = cart.total; (di mana total adalah field u32), apa hasil dari total.amount?

2. Apa arti {integer} di pesan error-nya?

3. let x = point.0; lalu x.0 menghasilkan E0610. Apa perbaikannya?

Skor: 0 / 3