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:

  1. Variabel pemilik harus dideklarasikan dengan mut — pemilik yang tidak boleh berubah jelas tidak bisa dipinjamkan izin mengubah.
  2. Pemanggil harus membuat reference dengan &mut value — tanda ini menjadi pernyataan eksplisit “pinjam saya untuk ditulis”.
  3. 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:

rust
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:

text
Nama lengkap: Budi Santoso

Ketiga syarat terpenuhi dan nilai aslinya berubah. Mari kita bedah kode di atas:

  1. Baris 1 (fn append_lastname(name: &mut String)): parameter name bertipe &mut String — syarat ketiga. Fungsi ini menyatakan terbuka bahwa fungsi tersebut akan mengubah teks pinjamannya.
  2. Baris 5 (let mut first_name = ...): variabel pemilik dideklarasikan mut — syarat pertama. Tanpa kata kunci ini, first_name adalah data beku yang tidak boleh diubah siapa pun.
  3. Baris 6 (append_lastname(&mut first_name);): pemanggil membuat reference mutable dengan &mut first_name — syarat kedua. Perhatikan bahwa kepemilikan tidak berpindah: first_name tetap sah dipakai pada baris berikutnya.
  4. Baris 2 (name.push_str(" Santoso");): di dalam fungsi, teks milik pemanggil diubah menjadi "Budi Santoso" langsung di heap milik first_name — tanpa penyalinan, tanpa nilai kembalian, tanpa kepemilikan yang hilir mudik.
  5. Baris 8 (println!("Nama lengkap: {}", first_name);): hasil perubahan tampak pada variabel asli. Bandingkan dengan fungsi add_degree pada Chapter Ownership di Fungsi yang harus mengembalikan String untuk 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:

rust
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:

text
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.

rust
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:

text
Daftar buah: Apel, Jeruk, Mangga

Mari kita bedah strateginya:

  1. Baris 5 ({): blok baru dibuka khusus sebagai ruang hidup pinjaman mutable. Teknik ini menjadikan niat menulis terlihat jelas dan terbatas.
  2. Baris 6 (let loan = &mut fruit_list;): loan menjadi satu-satunya penulis aktif. Selama blok ini berjalan, tidak ada pinjaman lain yang boleh dibuat terhadap fruit_list.
  3. Baris 7 (loan.push_str(", Mangga");): isi daftar bertambah menjadi "Apel, Jeruk, Mangga" — pemakaian terakhir sekaligus kesempatan terakhir loan.
  4. Baris 8 (}): blok ditutup. Peminjaman loan tamat di titik ini, sehingga fruit_list kembali bebas dipinjam dengan bentuk apa pun.
  5. 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:

  • &mut ketika 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.