Vec<T> (dibaca vector) adalah daftar yang panjangnya bisa bertambah dan berkurang saat program jalan, dengan semua isinya bertipe sama (T). Bayangin paku nota di dapur Kedai Martabak Bang Rusdi. Tiap pesanan baru ditusukkan di ujung, nota paling ujung bisa dicabut lagi, dan jumlahnya berubah sepanjang hari. Beda dengan papan harga menu, yang dicetak sekali dengan tepat tiga harga. Papan harga itu array ([u32; 3], panjangnya tetap), paku nota itu Vec<u32>.
🧪 Tebakan cepat: ada tiga pesanan hari ini, lalu kasir membaca pesanan nomor 3:
let pesanan = vec![102000, 70000, 38000]; println!("{}", pesanan[3]);Lolos compile? Kalau iya, apa yang tercetak? Tebak dulu, jawabannya ada di bagian "Membaca isi: [i] atau .get(i)".
Membuat Vec dan menambah isi
fn main() {
let mut pesanan: Vec<u32> = Vec::new();
pesanan.push(102000);
pesanan.push(70000);
pesanan.push(38000);
println!("{:?}", pesanan);
println!("Jumlah pesanan: {}", pesanan.len());
let harga = vec![32000, 38000, 5000];
println!("{:?}", harga);
}
[102000, 70000, 38000]
Jumlah pesanan: 3
[32000, 38000, 5000]
Vec::new()membuat Vec kosong. Tipe isinya ditulis diVec<u32>, karena dari Vec kosong compiler belum bisa menebaknya..push(nilai)menambah satu isi di ujung. Karena isinya berubah, variabelnya wajiblet mut.vec membuat Vec yang langsung berisi. Tipe isinya ditebak dari nilainya..len()memberi jumlah isinya.{:?}mencetak seluruh isi dengan kurung siku.{}biasa gak bisa mencetak Vec.
Kalau mut-nya lupa, push ditolak:
error[E0596]: cannot borrow `pesanan` as mutable, as it is not declared as mutable
--> src/main.rs:3:5
|
3 | pesanan.push(102000);
| ^^^^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
2 | let mut pesanan: Vec<u32> = Vec::new();
| +++
Membaca isi: [i] atau .get(i)
Isi Vec bernomor mulai dari 0, sama seperti array. Ada dua cara membacanya:
fn main() {
let pesanan = vec![102000, 70000, 38000];
println!("{}", pesanan[0]);
println!("{:?}", pesanan.get(1));
println!("{:?}", pesanan.get(3));
println!("{}", pesanan[3]);
}
$ cargo run
Compiling kedai v0.1.0 (/home/kamu/kedai)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s
Running `target/debug/kedai`
102000
Some(70000)
None
thread 'main' (23382854) panicked at src/main.rs:6:27:
index out of bounds: the len is 3 but the index is 3
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
pesanan[0]langsung memberi isinya:102000.pesanan.get(1)memberiSome(70000): isinya ada.pesanan.get(3)memberiNone: nomor 3 gak ada, dan programnya jalan terus. IniOptionyang kamu lihat sekilas di pelajaran match.pesanan[3]lolos compile, karena panjang Vec baru diketahui saat program jalan. Saat jalan, program panic (berhenti) denganindex out of bounds: the len is 3 but the index is 3. Isinya cuma nomor 0, 1, dan 2. Itu jawaban tebakannya: lolos compile, lalu crash, gak ada angka yang tercetak dari baris itu.- Pakai
[i]kalau nomornya pasti ada. Pakai.get(i)(lalumatch) kalau nomornya bisa saja di luar batas, misalnya dari input pembeli.
push, pop, sort, dan sum
fn main() {
let mut pesanan = vec![102000, 70000, 38000];
pesanan.push(45000);
println!("{:?} len {}", pesanan, pesanan.len());
let terakhir = pesanan.pop();
println!("{:?}", terakhir);
pesanan.sort();
println!("{:?}", pesanan);
let total: u32 = pesanan.iter().sum();
println!("Total hari ini: {}", total);
for p in &pesanan {
println!("Pesanan: {}", p);
}
}
[102000, 70000, 38000, 45000] len 4
Some(45000)
[38000, 70000, 102000]
Total hari ini: 210000
Pesanan: 38000
Pesanan: 70000
Pesanan: 102000
| Langkah | Isi pesanan sesudahnya |
len() |
|---|---|---|
vec![102000, 70000, 38000] |
[102000, 70000, 38000] |
3 |
push(45000) |
[102000, 70000, 38000, 45000] |
4 |
pop(), hasilnya Some(45000) |
[102000, 70000, 38000] |
3 |
sort() |
[38000, 70000, 102000] |
3 |
.pop()mencabut isi paling ujung dan memberikannya sebagaiSome(...). Dari Vec kosong, hasilnyaNone..sort()mengurutkan dari kecil ke besar, langsung di Vec itu sendiri. Ia juga butuhmut..iter().sum()menjumlahkan semua isi. Tipe hasilnya wajib ditulis:let total: u32.for p in &pesananmeminjam tiap isi, jadipesananmasih bisa dipakai sesudahnya.
Slice: sebagian Vec
fn main() {
let pesanan = vec![102000, 70000, 38000, 45000];
let tengah = &pesanan[1..3];
println!("{:?}", tengah);
let total: u32 = tengah.iter().sum();
println!("{}", total);
}
Output-nya [70000, 38000] lalu 108000. &pesanan[1..3] adalah slice: pinjaman ke sebagian isi, dari nomor 1 sampai sebelum 3, sama seperti range di for. Tipenya &[u32]. Gak ada yang disalin, slice cuma menunjuk ke isi Vec aslinya.
Vec berisi String dan ownership
Vec juga bisa berisi teks String. Bedanya dengan angka: push memindahkan String-nya ke dalam Vec.
fn main() {
let mut antrean: Vec<String> = Vec::new();
let nota = String::from("Martabak telur");
antrean.push(nota);
println!("{}", nota);
}
error[E0382]: borrow of moved value: `nota`
--> src/main.rs:5:20
|
3 | let nota = String::from("Martabak telur");
| ---- move occurs because `nota` has type `String`, which does not implement the `Copy` trait
4 | antrean.push(nota);
| ---- value moved here
5 | println!("{}", nota);
| ^^^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
4 | antrean.push(nota.clone());
| ++++++++
Notanya sekarang milik antrean. Baca lewat Vec-nya, antrean[0], atau push salinannya dengan nota.clone() kalau nota masih perlu dipakai.
📌 Kapasitas
Di balik layar, Vec memesan tempat lebih dari yang dipakai, supaya push gak perlu pindah tempat tiap kali. len() adalah isi yang dipakai, capacity() tempat yang sudah dipesan. Vec::with_capacity(100) memesan tempat 100 isi sejak awal: len() 0, capacity() 100. Berguna kalau kamu sudah tahu kira-kira berapa isinya.
⚠️ Jebakan yang sering ketemu
- Lupa
mut.push,pop, dansortditolak dengancannot borrow ... as mutable. - Nomor di luar batas.
v[i]panic saat jalan. Kalau nomornya belum pasti, pakaiv.get(i). - Mencetak Vec dengan
{}. Ditolak:`Vec<{integer}>` doesn't implement `std::fmt::Display`. Pakai{:?}. sum()tanpa tipe.let total = pesanan.iter().sum();ditolak dengantype annotations needed. Tulislet total: u32.- Memakai String setelah di-push. String-nya sudah pindah ke Vec.
TL;DR: Vec<T> adalah daftar setipe yang panjangnya bisa berubah: buat dengan Vec::new() atau vec![...], dan variabelnya let mut kalau isinya diubah. push menambah di ujung, pop mencabut dari ujung (Some(x) atau None), sort mengurutkan, len menghitung, iter().sum() menjumlah (tulis tipenya). v[i] panic kalau di luar batas (index out of bounds: the len is 3 but the index is 3), v.get(i) memberi Some atau None. Cetak dengan {:?}. &v[1..3] adalah slice, pinjaman ke nomor 1 dan 2. push memindahkan String ke dalam Vec.