Referensi yang kita pakai sejauh ini bersifat read-only: &String hanya bisa dibaca dan setiap upaya mengubah isinya langsung ditolak kompilator. Namun program nyata tidak hanya membaca — fungsi pengubah teks, pengisi data, dan penghitung bertambah semuanya perlu menulis. Untuk kebutuhan tersebut Rust menyediakan mutable reference dengan penulisan &mut T. Alat ini datang dengan tiga syarat yang harus dipenuhi sekaligus dan tetap tunduk pada aturan borrowing dari Chapter sebelumnya. Pada Chapter ini kita akan melengkapi kotak peralatan kita: mengubah data melalui pinjaman, membaca pesan error ketika syarat dilanggar, dan mengelola jangkauan pinjaman agar kode tetap diterima kompilator.
Tiga Syarat Referensi Mutable #
Membuat pinjaman yang boleh menulis menuntut kesepakatan penuh dari seluruh pihak yang terlibat. Ada tiga tempat yang harus sama-sama menyatakan niatnya:
- Variabel pemilik harus dideklarasikan dengan
mut— pemilik yang tidak boleh berubah jelas tidak bisa dipinjamkan izin mengubah. - Pemanggil harus membuat reference dengan
&mut value— tanda ini menjadi pernyataan eksplisit “pinjam saya untuk ditulis”. - Parameter fungsi harus bertipe
&mut T— fungsi ikut mendeklarasikan bahwa fungsi tersebut berniat mengubah pinjaman.
Ketiga tanda ini membuat maksud pengubahan data terbaca jelas di kode. Berikut bentuk lengkapnya dalam satu contoh:
fn append_lastname(name: &mut String) {
name.push_str(" Santoso");
}
fn main() {
let mut first_name = String::from("Budi");
append_lastname(&mut first_name);
println!("Nama lengkap: {}", first_name);
}Output yang Dihasilkan:
Nama lengkap: Budi SantosoKetiga syarat terpenuhi dan nilai aslinya berubah. Mari kita bedah kode di atas:
- Baris 1 (
fn append_lastname(name: &mut String)): parameternamebertipe&mut String— syarat ketiga. Fungsi ini menyatakan terbuka bahwa fungsi tersebut akan mengubah teks pinjamannya. - Baris 5 (
let mut first_name = ...): variabel pemilik dideklarasikanmut— syarat pertama. Tanpa kata kunci ini,first_nameadalah data beku yang tidak boleh diubah siapa pun. - Baris 6 (
append_lastname(&mut first_name);): pemanggil membuat reference mutable dengan&mut first_name— syarat kedua. Perhatikan bahwa kepemilikan tidak berpindah:first_nametetap sah dipakai pada baris berikutnya. - Baris 2 (
name.push_str(" Santoso");): di dalam fungsi, teks milik pemanggil diubah menjadi"Budi Santoso"langsung di heap milikfirst_name— tanpa penyalinan, tanpa nilai kembalian, tanpa kepemilikan yang hilir mudik. - Baris 8 (
println!("Nama lengkap: {}", first_name);): hasil perubahan tampak pada variabel asli. Bandingkan dengan fungsiadd_degreepada Chapter Ownership di Fungsi yang harus mengembalikanStringuntuk mencapai efek serupa.
Perbandingan dengan pola ambil-dan-kembalikan ini penting: &mut memberikan efek mutasi tanpa biaya serah terima kepemilikan. Harganya adalah kepatuhan penuh pada aturan satu penulis pada satu waktu.
Kode yang Gagal: Variabel Pemilik Tidak Dinyatakan mut #
Pelanggaran paling awal biasanya terjadi di syarat pertama. Kode berikut lupa mut pada variabel — dan tidak dapat dikompilasi:
fn mark_important(message: &mut String) {
message.push_str(" - PENTING");
}
fn main() {
let note = String::from("Rapat besok pagi");
mark_important(&mut note);
println!("{}", note);
}Pesan error kompilator:
error[E0596]: cannot borrow `note` as mutable, as it is not declared as mutable
--> main.rs:7:20
|
7 | mark_important(&mut note);
| ^^^^^^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
6 | let mut note = String::from("Rapat besok pagi");
| +++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0596`.Pesan E0596 menunjuk baris 7 sebagai titik pelanggaran: &mut note mencoba meminjam izin menulis dari variabel yang tidak pernah diberi izin itu. Usulan perbaikannya tepat sasaran — tambahkan mut pada deklarasi note di baris 6. Kesalahan serupa juga muncul bila pemanggil lupa &mut dan hanya mengirim note (tipe tidak cocok, E0308), atau bila fungsi lupa &mut pada parameternya (usaha mengubah reference biasa, ditolak karena reference immutable bersifat read-only).
Membatasi Jangkauan Pinjaman Mutable #
Aturan borrowing menyatakan satu penulis pada satu waktu, dan prinsip NLL menyatakan pinjaman berakhir pada pemakaian terakhirnya. Gabungan keduanya memberi kita strategi ampuh: bungkus pinjaman mutable dalam blok tersendiri agar pinjamannya tamat sebelum pembaca datang.
fn main() {
let mut fruit_list = String::from("Apel, Jeruk");
{
let loan = &mut fruit_list;
loan.push_str(", Mangga");
}
let view = &fruit_list;
println!("Daftar buah: {}", view);
}Output yang Dihasilkan:
Daftar buah: Apel, Jeruk, ManggaMari kita bedah strateginya:
- Baris 5 (
{): blok baru dibuka khusus sebagai ruang hidup pinjaman mutable. Teknik ini menjadikan niat menulis terlihat jelas dan terbatas. - Baris 6 (
let loan = &mut fruit_list;):loanmenjadi satu-satunya penulis aktif. Selama blok ini berjalan, tidak ada pinjaman lain yang boleh dibuat terhadapfruit_list. - Baris 7 (
loan.push_str(", Mangga");): isi daftar bertambah menjadi"Apel, Jeruk, Mangga"— pemakaian terakhir sekaligus kesempatan terakhirloan. - Baris 8 (
}): blok ditutup. Peminjamanloantamat di titik ini, sehinggafruit_listkembali bebas dipinjam dengan bentuk apa pun. - Baris 10 (
let view = &fruit_list;): pinjaman immutable dibuat tanpa konflik karena sang penulis sudah lama selesai. Isi daftar hasil perubahan tercetak pada baris berikutnya.
Urutan penulis-dulu-pembaca-kemudian seperti ini adalah pola yang paling sering dipakai di kode Rust dunia nyata. Bayangkan versi nyatanya: sebuah fungsi memperbarui data pinjaman mutable lebih dulu, lalu bagian berikutnya dari program membaca hasilnya dengan tenang.
Kapan Memilih &mut Dibanding Alternatifnya #
Tiga mekanisme perubahan data kini lengkap di tangan kita, dan masing-masing punya tempatnya:
&mutketika pemanggil ingin mempertahankan kepemilikan sambil meminta fungsi mengubah isinya — mutasi langsung, tanpa salinan.- Memindahkan kepemilikan (
String) ketika data lama memang sudah tidak dibutuhkan pemanggil dan fungsi akan mengembalikan wujud baru — misalnya fungsi pembangun nilai. clone()ketika pemanggil butuh data asli tetap utuh sekaligus salinan yang sudah diubah.
Ringkasan #
Referensi mutable melengkapi peminjaman dengan kemampuan menulis lewat &mut T, dengan syarat mut pada pemilik, &mut di pemanggilan, dan &mut pada parameter. Pelanggaran syarat menghasilkan E0596 lengkap dengan usulan perbaikan, sedangkan konflik antar pinjaman tetap dijaga aturan borrowing dan prinsip NLL. Membungkus pinjaman mutable dalam blok tersendiri menjaga jangkauannya pendek dan kode kita bebas konflik. Satu ancaman terakhir belum kita temui secara langsung: referensi yang hidup lebih lama dari data yang dipinjamnya — kasus dangling reference yang menjadi penutup section ini.