# Smart Pointer Rust Dijelaskan: Box, Rc, Arc, dan RefCell di 2026 > Smart pointer Rust Box, Rc, Arc, dan RefCell dijelaskan dengan contoh 2026 yang dapat dikompilasi, tabel keputusan, dan pertanyaan wawancara yang umum. - Published: 2026-07-05 - Updated: 2026-07-07 - Author: SharpSkill - Tags: rust, smart-pointers, memory-management, interview, rust-2024-edition - Reading time: 11 min --- Smart pointer di Rust adalah perkakas yang membuka pola kepemilikan yang tidak bisa diungkapkan oleh borrow checker sendirian: alokasi heap, kepemilikan bersama, dan mutasi di balik sebuah referensi bersama. Ketika sebuah referensi biasa (`&T`) hanya meminjam sebuah nilai, sebuah smart pointer memiliki datanya dan menambahkan perilaku ekstra di atasnya. Panduan ini menguraikan empat tipe yang ditemui setiap pengembang Rust di produksi maupun dalam wawancara: `Box`, `Rc`, `Arc`, dan `RefCell`, dengan contoh yang dapat dikompilasi menargetkan Rust edisi 2024. > **Ringkasan satu baris** > > Gunakan `Box` untuk alokasi heap dengan pemilik tunggal, `Rc` untuk kepemilikan bersama pada satu thread, `Arc` untuk kepemilikan bersama antar-thread, dan `RefCell` untuk memutasi sebuah nilai melalui referensi bersama. Pasangan `Rc>` dan `Arc>` menangani keadaan bersama yang dapat diubah. ## Apa itu smart pointer di Rust Sebuah smart pointer adalah struct yang berperilaku seperti pointer tetapi membawa metadata atau kemampuan ekstra. Sebagian besar mengimplementasikan trait `Deref`, sehingga `*pointer` dan pemanggilan metode bekerja seolah-olah pointer tersebut adalah referensi biasa, serta trait `Drop`, sehingga pembersihan berjalan otomatis ketika nilai keluar dari scope. Pustaka standar menyediakan keempat tipe yang dibahas di sini, dan memahaminya bergantung pada penguasaan yang kuat atas [kepemilikan dan peminjaman](/blog/rust/ownership-borrowing-rust-complete-guide), yang menentukan siapa yang membebaskan setiap alokasi dan kapan. Perbedaan utama dari sebuah referensi adalah kepemilikan. `&T` tidak pernah memiliki data yang ditunjuknya, sehingga ia tidak bisa hidup lebih lama daripada nilainya. Sebuah smart pointer memiliki datanya, mengendalikan masa hidupnya, dan membebaskannya secara deterministik. [Bab Rust Book tentang smart pointer](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html) memperlakukannya sebagai satu kategori justru karena mereka berbagi bentuk kepemilikan-plus-perilaku ini. ## `Box`: alokasi heap untuk tipe rekursif dan bertipe pasti `Box` adalah smart pointer yang paling sederhana. Ia menyimpan sebuah nilai di heap dan menyimpan pointer ke nilai itu di stack, dengan satu pemilik dan tanpa overhead runtime selain alokasi itu sendiri. Tugasnya yang paling umum adalah memberi tipe rekursif ukuran yang diketahui: sebuah tipe yang memuat dirinya sendiri secara langsung akan menjadi tak terhingga besar, tetapi sebuah `Box` hanyalah sebuah pointer, sehingga ukurannya tetap terlepas dari apa yang ditunjuknya. Contoh di bawah mendefinisikan sebuah pohon biner. Setiap `Node` memuat dua anak, dan tanpa indireksi kompiler tidak dapat menghitung ukuran `Tree`. Membungkus setiap anak dalam sebuah `Box` memutus rekursi di tingkat tipe. ```rust // tree.rs #[derive(Debug)] enum Tree { Leaf(i32), // Box puts each child on the heap, so Node has a fixed size (two pointers). Node(Box, Box), } fn sum(tree: &Tree) -> i32 { match tree { Tree::Leaf(value) => *value, // base case: return the leaf Tree::Node(left, right) => sum(left) + sum(right), // recurse into both children } } fn main() { // Build (1) + ((2) + (3)) = 6 let tree = Tree::Node( Box::new(Tree::Leaf(1)), Box::new(Tree::Node( Box::new(Tree::Leaf(2)), Box::new(Tree::Leaf(3)), )), ); println!("sum = {}", sum(&tree)); // sum = 6 } ``` `Box` juga penting ketika memindahkan sebuah nilai besar akan mahal, atau ketika mengembalikan sebuah trait object seperti `Box`. Dalam setiap kasus aturannya sama: satu pemilik, dibebaskan otomatis ketika `Box` di-drop. ## `Rc`: kepemilikan bersama pada kode single-thread Terkadang sebuah nilai membutuhkan beberapa pemilik, dan tak satu pun di antaranya jelas menjadi yang terakhir menggunakannya. `Rc` (reference counted) menyelesaikan ini dengan menyimpan hitungan kuat berapa banyak pemilik yang ada. `Rc::clone` menaikkan hitungan itu tanpa menyalin data yang mendasarinya, dan setiap drop menurunkannya. Ketika hitungan mencapai nol, nilainya dibebaskan. Bayangkan sebuah objek konfigurasi yang dibaca oleh beberapa worker. Setiap worker harus memegang konfigurasi selama masih dibutuhkan, dan alokasinya baru boleh hilang ketika worker terakhir sudah tiada. ```rust // shared_config.rs use std::rc::Rc; #[derive(Debug)] struct Config { endpoint: String, timeout_ms: u32, } fn main() { // Rc::new moves Config onto the heap with a strong count of 1. let config = Rc::new(Config { endpoint: "https://api.example.com".to_string(), timeout_ms: 5000, }); // Rc::clone only bumps the reference count; it does not deep-copy Config. let worker_a = Rc::clone(&config); let worker_b = Rc::clone(&config); // All three handles point to the same allocation. println!("endpoint: {}", worker_a.endpoint); println!("timeout: {}", worker_b.timeout_ms); // strong_count reports how many owners currently hold the value. println!("owners: {}", Rc::strong_count(&config)); // owners: 3 } ``` Memanggil `Rc::clone` secara eksplisit (alih-alih `config.clone()`) adalah idiomatik: ia memberi sinyal kepada pembaca bahwa operasi ini murah dan hanya menyentuh sebuah penghitung. Tangkapannya adalah `Rc` hanya memberikan referensi bersama yang immutable. Ia tidak dapat memutasi nilai yang dibagikannya, dan tidak aman dikirim antar-thread. [Dokumentasi `Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html) menjelaskan kedua batasan tersebut. ## `RefCell` dan mutabilitas interior di Rust Rust secara normal menegakkan bahwa sebuah nilai entah dibagikan melalui banyak referensi immutable atau dimutasi melalui tepat satu referensi mutable, dan ia memeriksanya pada waktu kompilasi. `RefCell` menyediakan mutabilitas interior: ia memungkinkan kode memutasi sebuah nilai melalui referensi bersama dengan memindahkan pemeriksaan yang sama itu ke waktu runtime. `borrow()` mengembalikan sebuah guard baca bersama; `borrow_mut()` mengembalikan sebuah guard tulis eksklusif. Aturannya identik, tetapi pelanggaran memicu panic alih-alih gagal dikompilasi. Digabung dengan `Rc`, ini menghasilkan pola bersama-mutable single-thread yang kanonik, `Rc>`: beberapa pemilik yang semuanya dapat memperbarui nilai yang sama. ```rust // counter.rs use std::rc::Rc; use std::cell::RefCell; // Rc gives shared ownership; RefCell allows mutation through a shared reference. type SharedCounter = Rc>; fn increment(counter: &SharedCounter) { // borrow_mut() hands out an exclusive reference, checked at runtime. *counter.borrow_mut() += 1; } fn main() { let counter: SharedCounter = Rc::new(RefCell::new(0)); let handle_a = Rc::clone(&counter); let handle_b = Rc::clone(&counter); increment(&handle_a); increment(&handle_b); increment(&counter); // borrow() gives a shared read guard; the value is now 3. println!("count = {}", counter.borrow()); // count = 3 } ``` > **RefCell memindahkan pemeriksaan peminjaman ke runtime** > > Memanggil `borrow_mut()` selagi sebuah guard `borrow()` atau `borrow_mut()` lain masih hidup akan memicu panic dengan `already borrowed: BorrowMutError`. Jaminan keamanan tetap berlaku, tetapi bug logika yang seharusnya ditangkap kompiler berubah menjadi crash pada waktu runtime. Jaga agar guard berumur pendek dan hindari menahan sebuah borrow melintasi pemanggilan fungsi yang mungkin masuk kembali ke `RefCell` yang sama. Mutabilitas interior juga tempat siklus referensi bersembunyi. Dua nilai `Rc>` yang saling menunjuk membuat hitungan kuat satu sama lain tetap di atas nol selamanya, sehingga tak satu pun pernah dibebaskan. Solusinya adalah `Weak`, sebuah handle non-pemilik yang tidak memengaruhi hitungan kuat; penjelasan klasiknya ada di [Learn Rust With Entirely Too Many Linked Lists](https://rust-unofficial.github.io/too-many-lists/). ## `Arc`: penghitungan referensi yang aman-thread untuk konkurensi `Arc` (atomically reference counted) adalah saudara multi-thread dari `Rc`. API publiknya nyaris identik, tetapi penghitungnya menggunakan operasi atomik, sehingga mengkloning dan men-drop sebuah `Arc` dari beberapa thread sekaligus tetap benar. Keatomikan itulah alasan `Arc` dipilih hanya ketika berbagi melintasi batas thread: kenaikan atomik terukur lebih lambat daripada kenaikan biasa yang digunakan `Rc`. Karena `Arc` tetap memberikan referensi immutable, mutasi antar-thread membutuhkan sebuah primitif sinkronisasi. `Mutex` adalah pasangan yang lazim, memberikan pola `Arc>` yang mencerminkan `Rc>` untuk kode konkuren. Contoh berikut memunculkan empat thread yang masing-masing menaikkan sebuah total bersama seribu kali. ```rust // parallel_sum.rs use std::sync::{Arc, Mutex}; use std::thread; fn main() { // Arc is safe to share across threads; Mutex serializes access to the inner value. let total = Arc::new(Mutex::new(0u64)); let mut handles = Vec::new(); for _ in 0..4 { // Each thread gets its own Arc handle (an atomic count bump). let total = Arc::clone(&total); handles.push(thread::spawn(move || { for _ in 0..1000 { // lock() blocks until the mutex is free, then returns a guard. let mut value = total.lock().unwrap(); *value += 1; } })); } for handle in handles { handle.join().unwrap(); // wait for every thread before reading } println!("total = {}", *total.lock().unwrap()); // total = 4000 } ``` Kompiler menegakkan batas itu secara otomatis: `Rc` bukan `Send`, sehingga mencoba memindahkannya ke dalam `thread::spawn` gagal dikompilasi, mendorong penggunaan `Arc`. Menggunakan `Arc` di dalam satu thread hanya membayar operasi atomik yang tak pernah dipakai. [Dokumentasi `Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) membahas jaminan pengurutan memori secara rinci, dan `Arc>` menopang sebagian besar keadaan bersama dalam [Rust async dengan Tokio](/blog/rust/rust-async-await-tokio-futures-concurrency). ## Box vs Rc vs Arc vs RefCell: kapan menggunakan masing-masing Keempat tipe tersusun di sepanjang dua sumbu: berapa banyak pemilik yang dimiliki sebuah nilai, dan apakah ia dapat dimutasi melalui sebuah handle bersama. Tabel berikut merangkum trade-off-nya. | Tipe | Kepemilikan | Mutasi via handle bersama | Aman-thread | Overhead | |------|-----------|----------------------------|-------------|----------| | `Box` | Tunggal | Tidak | Ya, jika `T: Send` | Hanya alokasi heap | | `Rc` | Bersama | Tidak | Tidak | Hitungan non-atomik | | `Arc` | Bersama | Tidak | Ya | Hitungan atomik | | `RefCell` | Tunggal | Ya (dicek saat runtime) | Tidak | Flag peminjaman runtime | Pohon keputusan praktisnya singkat. Butuh satu pemilik di heap: `Box`. Butuh banyak pemilik pada satu thread: `Rc`. Butuh banyak pemilik antar-thread: `Arc`. Butuh memutasi sebuah nilai bersama: bungkus tipe dalamnya dengan `RefCell` (single-thread) atau `Mutex` (multi-thread). Panduan Effective Rust tentang [tipe referensi dan pointer](https://www.lurklurk.org/effective-rust/) mencapai penataan yang sama. Mulailah dengan opsi paling tidak berkuasa dan tambahkan kemampuan hanya ketika kompiler memaksanya. ## Pertanyaan wawancara smart pointer Rust Smart pointer adalah topik wawancara yang andal karena menguji apakah seorang kandidat memahami kepemilikan alih-alih sekadar sintaks. Pertanyaan-pertanyaan di bawah sering muncul, dan lebih banyak lagi dikumpulkan dalam [modul wawancara smart pointer Rust](/technologies/rust/interview-questions/smart-pointers). **Apa perbedaan antara `Rc` dan `Arc`?** Keduanya menyediakan kepemilikan bersama melalui penghitungan referensi. `Rc` menggunakan penghitung non-atomik dan terbatas pada satu thread; `Arc` menggunakan operasi atomik dan dapat dibagikan antar-thread dengan biaya runtime kecil. Kompiler menegakkan pemisahan itu: `Rc` bukan `Send` maupun `Sync`, sehingga tidak dapat melintasi batas thread. **Mengapa menggabungkan `Rc` dengan `RefCell`?** `Rc` memberikan kepemilikan bersama tetapi hanya akses immutable. `RefCell` menambahkan mutabilitas interior, memungkinkan pemilik memutasi nilai melalui referensi bersama dengan pemeriksaan peminjaman runtime. Bersama-sama, `Rc>` adalah blok penyusun bersama-mutable single-thread yang idiomatik. **Bagaimana penghitungan referensi bisa membocorkan memori di Rust?** Dua nilai `Rc` (atau `Arc`) yang saling mereferensikan membentuk sebuah siklus yang hitungan kuatnya tidak pernah mencapai nol, sehingga alokasinya tidak pernah dibebaskan. Memutus siklus dengan `Weak`, yang memegang referensi non-pemilik, memulihkan pembersihan yang benar. **Kapan `Box` lebih disukai daripada `Rc`?** Kapan pun satu pemilik sudah cukup. `Box` tidak memiliki overhead penghitungan referensi, sehingga menjadi pilihan default untuk alokasi heap, tipe rekursif, dan trait object. Gunakan `Rc` hanya ketika kepemilikan bersama yang sesungguhnya diperlukan. ## Kesimpulan Smart pointer Rust mengubah kepemilikan dari sebuah batasan menjadi seperangkat blok penyusun yang dapat dikomposisi. Pilihan di antara mereka mengikuti langsung dari bentuk masalahnya: - Gunakan `Box` ketika sebuah nilai membutuhkan pemilik heap tunggal, sebuah tipe rekursif membutuhkan ukuran yang pasti, atau sebuah fungsi mengembalikan trait object. - Gunakan `Rc` untuk banyak pemilik pada satu thread, dan beralihlah ke `Arc` begitu kepemilikan melintasi batas thread. - Tambahkan `RefCell` untuk mutabilitas interior dalam kode single-thread, dan `Mutex` untuk padanan konkurennya, dengan menjaga guard peminjaman dan penguncian tetap berumur pendek. - Gabungkan secara sengaja: `Rc>` untuk keadaan bersama yang dapat diubah pada satu thread, `Arc>` antar-thread. - Waspadai siklus referensi antar pointer terhitung dan putuskan dengan `Weak` untuk menghindari kebocoran. - Default-kan ke tipe paling tidak berkuasa dan biarkan kompiler memberi tahu kapan lebih banyak kemampuan diperlukan. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/id/blog/rust/rust-smart-pointers-box-rc-arc-refcell