Slice Sebagai Reference Pada Rust

Slice adalah salah satu cara mudah bagi kita untuk meminjam sebagian nilai pada rust. Terkadang kita tidak ingin meminjam semua barang teman kita karena yang diperlukan hanya satu atau beberapa barang saja.

Pendahuluan

Dalam rangka memahami fungsi dari slice kita akan memulainya dengan sebuah permasalahan yang ditawarkan oleh The Book: Rust Proglamming Language.

Seorang mahasiswi ingin membuat program yang menampilkan kata pertama pada suatu kalimat. Hal ini dapat dilakukan dengan mendeteksi spasi pertama pada kalimat tersebut. Kemudian memanggil index-nya.

Study case

fn main() {

    let mut kalimat = String::from("I am become the death");
    let hasil = kata_pertama(&kalimat);
    kalimat.clear();

    println!("{}", hasil)
    }

fn kata_pertama (x: &String) -> usize {
    let convert = x.as_bytes();
    for (i, &item) in convert.iter().enumerate(){
        if item == b' '{
            return i;
        }
    }
    x.len()
}

Contoh 1.0

fn kata_pertama akan menghasilkan return value berupa posisi index untuk spasi. Hanya saja, masalah kita belum terpecahkan sepenuhnya karena let convert = x.as_bytes(); akan menghasilkan bytes array berdasarkan standar ASCII yang bisa berdiri sendiri. Tidak lagi terhubung dengan x.

for (i, &item) in convert.iter().enumerate(){
        if item == b' '{
            return i;
        }

for digunakan untuk mencari posisi spasi berdasarkan ASCII baik base decimal atau binary. Value hasil dari iterasi .iter( ) dan .enumerate( ) akan disandingkan dengan variabel i dan &item.

Secara default .iter( ) akan menggunakan referensi kepada data asli berupa &u8. Maka dari itu dibutuhkan variabel &item untuk melakukan dereferencing. Kita membandingkan dengan b ‘ ‘ yang merupakan u8. Bila tidak di-deref maka &u8 dibandingkan dengan u8.

Rust tidak dapat membandingkan data referensi dengan data non-referensi. Misal &u8 + u8 tidak akan berhasil dieksekusi karena keduanya berbeda.

x.len( ) merupakan pilihan opsional bilamana tidak terdapat spasi (satu kata saja). Perhatikan if pada for terdapat return i; yang berfungsi mengembalikan suatu nilai bila memenuhi syarat.

return membuat kode setelahnya tidak dieksekusi, yaitu x.len( ) karena fungsi akan menggunakan i sebagai return value. Bila spasi tidak ditemukan maka return tidak ter-trigger, x.len( ) akan berfungsi.

Index spasi yang dikembalikan memiliki tipe data usize. Secara tidak langsung, kita telah mengetahui panjang dari kata tersebut. Tetapi belum didapatkan kata pertamanya.

  kalimat.clear();

Contoh 1.0 dapat menghasilkan bug, ketika kalimat tidak memiliki String karena dihapus oleh kalimat.clear();. Value 1 tetap dapat dihasilkan padahal String sudah tidak ada. Oleh karena itu, tidak ada jaminan bahwa index tersebut akan tetap valid.

Slice

Slice adalah reference yang dapat meminjam sebagian value pada elemen-elemen yang berdekatan. Slice tidak bisa meminjam value terhadap elemen yang memiliki gap.

There is conflicting nomenclature around slices. Some will call, &str a “slice”, others will call it a “slice reference” or “reference to a slice” and consider str to be the type for “slices”. The & in the type is to distinguish to other ways of referencing or owning string slices, like &mut str (rarely used) or Box<str> or Arc<str> for example.

The & in the slicing expression &s[0..2] is to distinguish from creation of mutable slices via &mut s[0..2] of type &mut str. For string slices, these are rarely used, because they’re not super useful, but for the slice type [T], both types &[T] and &mut [T] are commonly used, and the slicing syntax there goes through the same mechanism: the Index (or IndexMut) trait. Which is concerned with more than just slicing. If you call &v[i] or &mut v[i] or v[i] on a vector or array, you’ll get references or copies of the value at a given index. The & has meaning and distinguishes various cases.

Steffahn – Rust forum moderator
fn main() {
    let x = String::from("Qori notes");
    let contoh_slice1 = &x[0..4];
    let contoh_slice2 = &x[..4];

    println!("{} {}", contoh_slice1, contoh_slice2);
}

Contoh 1.1

Terdapat beberapa cara untuk melakukan slice, yaitu menggunakan index awal + panjang kata [0..4] atau panjang kata saja [..4]. index awal adalah 0 dan panjang kata 4.

Kata Qori pada gambar di atas adalah slice dari Qori notes. Kita tidak bisa melakukan slice Qoes.

Menggunakan len dalam slice

fn main() {
    let main = String::from("Qori Notes");
    let len = main.len();
    let slice = &main[5..len];
    let slice2 = &main[..len];
    let slice3= &main[..];
  
    println!("{} {} {}", slice, slice2, slice3);
}

Contoh 1.3

Penggunaan len() dapat digunakan untuk menggantikan akhiran slice tetapi sangat bersifat kondisional. Hal ini karena len() akan menghitung panjang satu kalimat, bukan kata.

Solusi Permasalahan

fn kata_pertama(x: &String) -> &str {

    let convert = x.as_bytes();

    for (i, &item) in convert.iter().enumerate() {
      if item == b' '{

      return &x[0..i];}
    }
&x[..]
}

Contoh 1.4

Setelah diganti menggunakan slice, bug pada contoh 1.0 tidak akan terjadi karena compiler segera mencegahnya dengan memberikan pesan error.

error[E0502]: cannot borrow `kalimat` as mutable because it is also borrowed as immutable
 --> src/main.rs:4:5
  |
3 |     let hasil = kata_pertama(&kalimat);
  |                              -------- immutable borrow occurs here
4 |     kalimat.clear();
  |     ^^^^^^^^^^^^^^^ mutable borrow occurs here
5 |     println!("{}", hasil);
  |                    ----- immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `ownership` (bin "ownership") due to previous error

Contoh 1.5

Pada postingan sebelumnya mengenai immutable reference yang tidak mengizinkan penggunaan immutable dan mutable reference secara bersamaan.

kalimat.clear(); adalah mutable reference yang akan menghapus value. Kemudian kita melakukan immutable reference pada saat memanggil fungsi let hasil = kata_pertama(&kalimat);.

Setelah menghapus mut pada variabel kalimat dan kalimat.clear(); output dari contoh 1.5 adalah sebagai berikut.

I

Contoh 1.6

Kata pertama dari kalimat I am become the death adalah I. Dari program tersebut kita dapat mengetahui mengenai standar ASCII dan UTF-8 yang menyimpan setiap karakter dan mewakilkannya dengan angka.

Penutup

Slice benar-benar membuat saya kebingungan, terlebih keseluruhan materi mengenai ownership. Tetapi dengan terus mencoba akhirnya saya bisa menyampaikan kembali materi mengenai slice.

Beberapa sumber yang saya sarankan untuk dibaca dalam rangka memahami slice:


Discover more from Qorinotes

Subscribe to get the latest posts sent to your email.

Qori Avatar

Published by

Categories: