Pelajaran modul (2/2)
Petunjuk Cerdas: Kotak dan Rc
smart pointer adalah struktur data yang berperilaku seperti pointer, namun memiliki metadata dan kemampuan tambahan (seperti penghitungan referensi atau manajemen memori otomatis).
Di Rust, referensi biasa (seperti &) hanya meminjam data. Sebaliknya, penunjuk cerdas sering kali memiliki data yang ditunjuknya. Contoh umum mencakup String dan Vec<T>, namun perpustakaan standar menyediakan perpustakaan khusus lainnya.
Kotak<T> untuk Alokasi Heap
Penunjuk cerdas paling sederhana adalah Box<T>, yang menyimpan data di heap, bukan di tumpukan. Hanya penunjuk ke data yang dialokasikan heap yang tersisa di tumpukan.
Hal ini terutama digunakan dalam kasus-kasus berikut:
- Ketika Anda memiliki tipe yang ukurannya tidak dapat diketahui pada waktu kompilasi (seperti tipe rekursif), dan Anda ingin menggunakan nilai tipe tersebut dalam konteks yang memerlukan ukuran yang tepat.
- Saat Anda ingin mentransfer kepemilikan data dalam jumlah besar tanpa menyalinnya.
Contoh dasar:
fn main() {
let b = Box::new(5); // allocates the value 5 on the heap
println!("b = {}", *b); // dereferences with * to read the value
}Jenis Rekursif dan Daftar Kontra
Tipe rekursif adalah tipe yang dapat memuat nilai dirinya sendiri sebagai bagian dari definisinya. Rust harus mengetahui ukuran pasti suatu tipe pada waktu kompilasi. Karena kedalaman tipe rekursif bisa jadi tidak terbatas, kompiler menghasilkan kesalahan kecuali Anda menggunakan Kotak (yang memiliki ukuran tetap, karena merupakan penunjuk):
enum List {
Cons(i32, Box<List>),
Nil,
}Rc<T>: Penghitungan Referensi
Ada kalanya satu nilai dapat memiliki banyak pemilik. Penunjuk cerdas Rc<T> (Referensi Terhitung) melacak jumlah referensi ke suatu nilai untuk menentukan apakah nilai tersebut masih digunakan. Jika hitungannya turun ke nol, sumber daya akan dibatalkan alokasinya dengan aman.
[!CATATAN]
Rc<T>hanya cocok untuk skenario thread tunggal. Untuk skenario multi-thread (bersamaan), Anda harus menggunakanArc<T>(Referensi Atom Terhitung).
use std::rc::Rc;
fn main() {
let a = Rc::new(5);
let b = Rc::clone(&a); // increments the reference count to 2
println!("References: {}", Rc::strong_count(&a));
}Cobalah sendiri
Latihan 1: Alokasi Tumpukan dengan Kotak
Alokasikan nilai integer 42 di heap menggunakan Box::new dan tetapkan ke variabel bernama val. Selanjutnya, cetak nilai yang disimpan dalam Kotak dengan melakukan dereferensi secara eksplisit menggunakan operator *.
Tunjukkan petunjuk
Gunakan `let val = Box::new(42);` untuk menyimpan nilai di heap dan melakukan dereferensi dengan `*val` di dalam `println!`.
Solusi tersedia setelah 3 upaya
Latihan 2: Struktur Data Rekursif (Daftar Kontra)
Definisikan enum rekursif bernama Daftar yang berisi dua varian: Cons yang membungkus tuple (i32, Box<List>), dan Nil yang mewakili akhir daftar. Dalam fungsi utama, buat instance daftar tertaut yang berisi elemen 1 diikuti oleh Nil.
Tunjukkan petunjuk
Enum dideklarasikan sebagai `enum List { Cons(i32, Box<List>), Nil }`. Buat instance daftar dengan `List::Cons(1, Box::new(List::Nil))`.
Solusi tersedia setelah 3 upaya
Latihan 3: Berbagi Kepemilikan dengan Rc
Gunakan std::rc::Rc untuk membuat bilangan bulat bersama yang berisi nilai 100 dalam variabel a. Kloning referensi ke dalam variabel b menggunakan Rc::clone. Terakhir, cetak jumlah referensi aktif menggunakan fungsi Rc::strong_count.
Tunjukkan petunjuk
Buat nilai dengan `Rc::new(100)`. Kloning dengan `Rc::clone(&a)`dan tampilkan jumlah pemilik dengan`Rc::strong_count(&a)`.
Solusi tersedia setelah 3 upaya