Slice di Rust
Sebuah slice (potongan) memungkinkan kamu meminjam sebagian dari array atau vektor, semacam “jendela” ke sebagian datanya, tanpa menyalin data itu dan tanpa mengambil ownership-nya. Kalau kamu sudah pernah memakai borrowing (peminjaman) untuk satu nilai, slice adalah ide yang sama, hanya saja diterapkan pada sederet elemen.
Mengambil slice dari array
Section titled “Mengambil slice dari array”fn main() { let numbers = [10, 20, 30, 40, 50];
let middle = &numbers[1..4]; // elemen di indeks 1, 2, 3 println!("{:?}", middle);}Output:
[20, 30, 40]1..4 adalah jenis range yang sama dengan yang kamu lihat di perulangan for. Range ini mulai dari indeks 1 dan berhenti sebelum indeks 4, jadi kamu mendapat indeks 1, 2, dan 3.
Singkatan range untuk slice
Section titled “Singkatan range untuk slice”Beberapa jalan pintas yang sering muncul:
fn main() { let numbers = [10, 20, 30, 40, 50];
println!("{:?}", &numbers[..3]); // dari awal sampai indeks 3 -> [10, 20, 30] println!("{:?}", &numbers[2..]); // dari indeks 2 sampai akhir -> [30, 40, 50] println!("{:?}", &numbers[..]); // seluruhnya -> [10, 20, 30, 40, 50]}Slice string
Section titled “Slice string”Sebenarnya kamu sudah memakai slice dari tadi: &str adalah slice dari sebuah String (atau dari string lain)! Itulah sebabnya kedua tipe ini bisa bekerja sama dengan sangat baik:
fn main() { let sentence = String::from("The quick brown fox");
let first_word = &sentence[0..3]; println!("{first_word}"); // "The"}Kalimatnya sengaja dibiarkan dalam bahasa Inggris: [0..3] memotong berdasarkan posisi byte, jadi kalau teksnya diganti, hasil potongannya juga ikut berubah.
Kenapa slice, bukan menyalin?
Section titled “Kenapa slice, bukan menyalin?”Kamu bisa saja menyelesaikan masalah ini dengan menyalin bagian yang kamu mau ke Vec atau String baru. Slice menghindari hal itu sama sekali: slice hanya menunjuk ke sebagian data yang sudah ada, sama seperti referensi (&) menunjuk ke satu nilai. Artinya tidak ada alokasi tambahan, tidak ada penyalinan, dan aturan borrowing yang sudah kamu kenal dari halaman Borrowing tetap berlaku.
Fungsi yang menerima slice
Section titled “Fungsi yang menerima slice”Slice sangat berguna sebagai parameter fungsi, karena bisa menerima array maupun vektor:
fn sum(numbers: &[i32]) -> i32 { let mut total = 0; for n in numbers { total += n; } total}
fn main() { let array = [1, 2, 3]; let vector = vec![4, 5, 6];
println!("{}", sum(&array)); println!("{}", sum(&vector));}&[i32] menerima slice dari array maupun dari Vec. Satu fungsi, dan kedua pemanggilan sama-sama berhasil.
Mengubah data lewat slice mutable
Section titled “Mengubah data lewat slice mutable”Sejauh ini slice kita hanya membaca data. Sebuah slice mutable, &mut [T], memungkinkan fungsi mengubah item yang diberikan kepadanya, tetapi hanya item-item itu saja:
fn double_all(numbers: &mut [i32]) { for i in 0..numbers.len() { numbers[i] *= 2; }}
fn main() { let mut scores = vec![1, 2, 3, 4, 5];
double_all(&mut scores[1..3]); // hanya indeks 1 dan 2 println!("{:?}", scores);
double_all(&mut scores); // seluruh vektor println!("{:?}", scores);}Output:
[1, 4, 6, 4, 5][2, 8, 12, 8, 10]Pemanggilan pertama mengirim &mut scores[1..3], jadi double_all hanya melihat indeks 1 dan 2. Semua yang ada di luar range itu aman darinya. Di dalam fungsi, slice-nya mulai lagi dari indeks 0: bagi double_all, itu hanyalah daftar berisi dua angka.
Ini aman karena sebuah aturan yang akan kamu pelajari lebih dalam di halaman Borrowing: selama fungsi memegang slice &mut, tidak ada bagian lain yang boleh memakai item-item itu, jadi dua bagian kode tidak akan pernah bisa mengubahnya bersamaan. Vektornya juga harus dideklarasikan dengan mut, kalau tidak Rust tidak akan mengizinkan kamu meminjamnya secara mutable.
Latihan
Section titled “Latihan”1. Bagi dua
Section titled “1. Bagi dua”Buat vektor vec![3, 6, 9, 12, 15, 18]. Cetak paruh pertama dan paruh keduanya sebagai dua slice terpisah. Petunjuk: hitung let mid = numbers.len() / 2; lalu pakai ..mid dan mid...
Lihat solusi
fn main() { let numbers = vec![3, 6, 9, 12, 15, 18]; let mid = numbers.len() / 2;
let first_half = &numbers[..mid]; let second_half = &numbers[mid..];
println!("Paruh pertama: {:?}", first_half); println!("Paruh kedua: {:?}", second_half);}Output:
Paruh pertama: [3, 6, 9]Paruh kedua: [12, 15, 18]Karena mid dihitung dari len(), kode ini tetap benar walaupun kamu menambah atau menghapus angka. Kalau panjangnya ganjil, item sisanya masuk ke paruh kedua.
2. Angka terbesar di daftar apa pun
Section titled “2. Angka terbesar di daftar apa pun”Tulis fungsi largest(numbers: &[i32]) -> i32 yang mengembalikan angka terbesar. Panggil fungsi itu dengan sebuah array, dengan sebuah vektor, dan dengan slice yang hanya berisi item pertama dari vektor tersebut. Petunjuk: mulai dari numbers[0] lalu ulangi sisanya, seperti yang biasa kamu lakukan pada array.
Lihat solusi
fn largest(numbers: &[i32]) -> i32 { let mut biggest = numbers[0]; for n in numbers { if *n > biggest { biggest = *n; } } biggest}
fn main() { let array = [7, 2, 9, 4]; let vector = vec![10, 35, 21];
println!("{}", largest(&array)); println!("{}", largest(&vector)); println!("{}", largest(&vector[..1]));}Output:
93510Saat kamu melakukan perulangan pada slice, kamu mendapat referensi ke setiap item (&i32), bukan angkanya langsung. *n artinya “nilai yang ditunjuk oleh n”, jadi *n > biggest membandingkan dua angka biasa. Versi ini akan panic kalau slice-nya kosong, karena numbers[0] tidak ada. Nanti kamu akan belajar mengembalikan Option untuk kasus seperti itu.
Ringkasan
Section titled “Ringkasan”- Slice (
&[T]) meminjam sebagian array atau vektor tanpa menyalinnya. 1..4memilih indeks 1 sampai 3; hilangkan salah satu sisi..untuk mulai dari awal atau berjalan sampai akhir.&strsendiri adalah slice dari teks, itulah sebabnya string dan slice punya banyak perilaku yang sama.- Pakai
&[T]sebagai tipe parameter fungsi kalau kamu ingin menerima array maupun vektor. - Slice mutable (
&mut [T]) memungkinkan fungsi mengubah hanya item yang diberikan kepadanya.
Kuis singkat
Section titled “Kuis singkat”Kuis singkat
1. Apa yang bisa kamu lakukan dengan slice terhadap sebagian array atau vektor?
2. Indeks mana saja yang termasuk dalam &numbers[1..4]?
3. Kenapa &[i32] pilihan yang baik untuk tipe parameter fungsi?
Skor: 0 / 3
Bacaan lebih lanjut
Section titled “Bacaan lebih lanjut”- The Slice Type — The Rust Book (bahasa Inggris): membangun konsep slice langkah demi langkah dengan contoh “kata pertama dari sebuah string”.
- Arrays and Slices — Rust by Example (bahasa Inggris): contoh yang bisa dijalankan tentang meminjam array sebagai slice.
slice— dokumentasi standard library (bahasa Inggris): banyak method yang dimiliki slice, sepertifirst,split_at,contains, dansort.- Slice types — The Rust Reference (bahasa Inggris): definisi persisnya, kalau kamu ingin tahu arti tepat dari
[T]dan&[T].