Error Rust E0515: cannot return reference to local variable (referensi lokal)
E0515 artinya: fungsimu mencoba mengembalikan referensi (&) ke sesuatu yang ia buat sendiri. Semua yang dibuat oleh sebuah fungsi dibersihkan saat fungsi itu selesai, jadi referensinya akan menunjuk ke ketiadaan. Hampir setiap pemula Rust pernah kena error ini, dan perbaikannya biasanya cukup menghapus satu & lalu mengembalikan nilainya langsung. (Halaman ini bagian dari Penjelasan error compiler Rust.)
Pesan error-nya
Section titled “Pesan error-nya”error[E0515]: cannot return reference to local variable `greeting` --> src/main.rs:3:5 |3 | &greeting // ❌ greeting di-drop saat fungsi selesai | ^^^^^^^^^ returns a reference to data owned by the current functionCompiler menunjuk &greeting dan bilang: ini mengembalikan referensi ke data yang dimiliki oleh fungsi ini sendiri.
Ini program yang menghasilkan error tersebut:
fn make_greeting(name: &str) -> &str { let greeting = format!("Hello, {name}!"); // String baru, dimiliki fungsi ini &greeting // ❌ greeting di-drop saat fungsi selesai}
fn main() { let text = make_greeting("Ferris"); println!("{text}");}Kamu akan melihat beberapa versi kalimat untuk error yang sama. Artinya sama semua:
cannot return reference to local variablekalau kamu menulis&greeting.cannot return value referencing local variablekalau kamu memanggil method yang meminjam, sepertigreeting.as_str()atau&scores[2..].cannot return value referencing temporary valuekalau datanya tidak pernah disimpan di variabel, sepertitext.to_uppercase().as_str().
Setiap versi membawa label “returns a value referencing data owned by the current function” (mengembalikan nilai yang merujuk ke data milik fungsi ini).
Apa artinya
Section titled “Apa artinya”greeting adalah variabel lokal: ia dibuat di dalam make_greeting dan dimiliki oleh fungsi itu. Saat fungsinya selesai, semua variabel lokalnya di-drop. &str yang kamu kembalikan akan menunjuk ke dalam String yang sudah tidak ada.
Ini seperti pindah dari kamar kos lalu memberikan kuncinya ke temanmu. Kuncinya memang asli, tapi kamarnya sudah kosong, atau sudah ditempati orang lain. Yang temanmu butuhkan adalah barang-barangnya, bukan kuncinya.
Cara yang sering membawamu ke sini: awalnya kamu mengembalikan greeting (sebuah String) dari fungsi yang tipe kembaliannya &str, lalu mendapat E0308 (tipe tidak cocok), dan compiler menyarankan “consider borrowing here: &greeting”. Saran itu membereskan tipenya, tapi langsung menjerumuskanmu ke E0515. Perbaikan yang sebenarnya adalah mengubah tipe kembaliannya.
Kenapa Rust melakukan ini
Section titled “Kenapa Rust melakukan ini”Sebuah referensi tidak boleh hidup lebih lama dari nilai yang ditunjuknya. Mengembalikan referensi ke variabel lokal akan menciptakan dangling reference, yaitu pointer ke memori yang sudah dibebaskan. Di C dan C++, kode seperti ini lolos kompilasi lalu crash (atau lebih parah, diam-diam mengembalikan data sampah). Rust menangkapnya saat kompilasi.
Referensi yang dikembalikan harus meminjam dari sesuatu yang hidup di luar fungsi: parameter yang diberikan pemanggil, field dari self, atau nilai 'static seperti string literal. Variabel lokal milik fungsi itu sendiri tidak memenuhi syarat. Karena itulah anotasi lifetime tidak bisa memperbaiki E0515: 'a hanya menjelaskan berapa lama data hidup, ia tidak bisa membuat variabel lokal hidup lebih lama. Lihat Ownership (kepemilikan) dan Borrowing (peminjaman).
Cara memperbaikinya
Section titled “Cara memperbaikinya”Perbaikan 1: Kembalikan nilai milik sendiri (owned)
Section titled “Perbaikan 1: Kembalikan nilai milik sendiri (owned)”Pilih ini kalau fungsinya membuat datanya. Ini jawaban yang tepat di sebagian besar kasus. Kembalikan String alih-alih &str (atau Vec<T> alih-alih &[T]) dan hapus &-nya. Nilainya dipindahkan (move) ke pemanggil, yang kemudian memilikinya:
fn make_greeting(name: &str) -> String { let greeting = format!("Halo, {name}!"); greeting // ✅ serahkan seluruh String ke pemanggil}
fn top_scores() -> Vec<u32> { let mut scores = vec![42, 97, 63, 88]; scores.sort(); scores.split_off(2) // dua nilai tertinggi, sebagai Vec baru}
fn main() { let text = make_greeting("Ferris"); println!("{text}"); println!("{:?}", top_scores());}Output:
Halo, Ferris![88, 97]Jangan khawatir soal biaya: mengembalikan String atau Vec hanya memindahkan pointer kecil, panjang, dan kapasitasnya. Teksnya sendiri tidak disalin. Kamu juga bisa langsung menulis format!("Halo, {name}!") sebagai baris terakhir.
Perbaikan 2: Terima datanya sebagai parameter dan kembalikan referensi ke dalamnya
Section titled “Perbaikan 2: Terima datanya sebagai parameter dan kembalikan referensi ke dalamnya”Pilih ini kalau pemanggil sudah memiliki datanya dan kamu hanya ingin menunjuk ke sebagiannya. Kalau fungsinya bekerja pada parameter pinjaman, referensi yang dikembalikan meminjam dari parameter itu, yang hidup di luar fungsi:
fn top_two(scores: &mut [u32]) -> &[u32] { scores.sort(); &scores[scores.len() - 2..] // ✅ menunjuk ke data milik pemanggil}
fn main() { let mut scores = vec![42, 97, 63, 88]; // dimiliki oleh main let best = top_two(&mut scores); println!("{best:?}");}Output:
[88, 97]Dengan satu parameter referensi, Rust mengisi lifetime-nya untukmu. Dengan dua atau lebih, kamu mungkin perlu 'a (lihat E0106). Cara ini hanya berhasil kalau kamu mengembalikan potongan dari input. Nilai yang benar-benar baru yang dibuat dari input (to_uppercase(), format!, trim().to_string()) adalah variabel lokal lagi, jadi kembali ke Perbaikan 1. Lihat Slice.
Perbaikan 3: Kembalikan &'static str untuk string literal
Section titled “Perbaikan 3: Kembalikan &'static str untuk string literal”Pilih ini kalau setiap kemungkinan hasilnya adalah teks tetap yang ditulis di kodemu. String literal disimpan di dalam program itu sendiri dan hidup selamanya, jadi mengembalikan referensi ke literal selalu aman:
fn status_text(code: u16) -> &'static str { match code { 200 => "OK", 404 => "Not Found", 500 => "Internal Server Error", _ => "Unknown", }}
fn main() { for code in [200, 404, 418] { println!("{code}: {}", status_text(code)); }}Output:
200: OK404: Not Found418: UnknownJangan mencoba “memperbaiki” hasil format! dengan menulis &'static str di signature. Kamu hanya akan mendapat E0515 lagi, karena String-nya tetap variabel lokal.
Perbaikan 4: Pakai Cow kalau kadang meminjam dan kadang membuat baru
Section titled “Perbaikan 4: Pakai Cow kalau kadang meminjam dan kadang membuat baru”Pilih ini kalau fungsinya biasanya mengembalikan input-nya tanpa perubahan, tapi kadang harus membuat string baru. Cow (clone-on-write) bisa berisi &str pinjaman atau String milik sendiri, jadi kamu hanya mengalokasikan memori kalau memang perlu:
use std::borrow::Cow;
fn safe_file_name(name: &str) -> Cow<'_, str> { if name.contains(' ') { Cow::Owned(name.replace(' ', "_")) // String baru hanya kalau perlu } else { Cow::Borrowed(name) // tidak ada salinan sama sekali }}
fn main() { for name in ["report.txt", "my notes.txt"] { let clean = safe_file_name(name); let kind = match clean { Cow::Borrowed(_) => "dipinjam", Cow::Owned(_) => "milik sendiri", }; println!("{clean} ({kind})"); }}Output:
report.txt (dipinjam)my_notes.txt (milik sendiri)Cow adalah optimasi. Kalau kamu tidak yakin membutuhkannya, kembalikan String saja (Perbaikan 1). Selengkapnya di Weak dan Cow.
Di mana biasanya kamu melihatnya
Section titled “Di mana biasanya kamu melihatnya”Mengembalikan s.as_str() dari String lokal. greeting.as_str() meminjam greeting, jadi gagal dengan cara yang sama seperti &greeting, dengan kalimat “cannot return value referencing local variable”. Perbaikan: kembalikan greeting dan jadikan tipe kembaliannya String.
.map() yang membuat string baru. Kelihatannya tidak berbahaya, tapi setiap to_lowercase() membuat String sementara yang langsung di-drop setelah .as_str():
fn tags(input: &str) -> Vec<&str> { input.split(',').map(|t| t.trim().to_lowercase().as_str()).collect() // ❌ cannot return value referencing temporary value}Perbaikan: kembalikan Vec<String> dan hapus .as_str(): .map(|t| t.trim().to_lowercase()).collect(). (Tanpa to_lowercase(), t.trim() adalah slice dari input, jadi Vec<&str> akan berhasil. Lihat Iterator.)
Method yang memformat field. fn full_name(&self) -> &str { &format!("{} {}", self.first, self.last) } memberi “cannot return reference to temporary value”. Perbaikan: -> String. Mengembalikan &self.first tidak masalah, karena data itu hidup di dalam struct, bukan di dalam method. Lihat Struct.
Fungsi tanpa parameter referensi. fn make_greeting() -> &String gagal lebih awal, dengan E0106, karena tidak ada apa pun yang bisa dipinjam. Perbaikannya sama: kembalikan String.
Error terkait
Section titled “Error terkait”- E0106: missing lifetime specifier: sering muncul duluan; menambahkan
'atidak akan memperbaiki referensi ke variabel lokal. - E0597: borrowed value does not live long enough: masalah yang sama di dalam satu fungsi, dengan blok atau perulangan alih-alih
return. - E0308: mismatched types: mengembalikan
Stringpadahal yang dideklarasikan&str. Ubah tipe kembaliannya, jangan menambahkan&. - E0382: borrow of moved value: setelah beralih ke nilai owned, hati-hati memakai nilai setelah kamu memindahkannya.
E0716: temporary value dropped while borrowed: referensi ke nilai sementara yang dipakai lagi nanti di fungsi yang sama.- Semua error compiler dijelaskan
Kuis singkat
Section titled “Kuis singkat”Kuis singkat
1. Sebuah fungsi membuat pesan dengan format! lalu mengembalikan &message. Apa perbaikan yang biasanya tepat?
2. Fungsi mana yang bisa dikompilasi?
3. Kapan Cow<str> cocok sebagai tipe kembalian?
Skor: 0 / 3
Bacaan lebih lanjut
Section titled “Bacaan lebih lanjut”- E0515 — Rust error codes index (bahasa Inggris): penjelasan resmi error ini.
- Dangling References — The Rust Book (bahasa Inggris): contoh
dangledan kenapa jawabannya adalah mengembalikanStringsecara langsung. - Validating References with Lifetimes — The Rust Book (bahasa Inggris): kenapa referensi yang dikembalikan harus terikat ke salah satu parameter.
- The Slice Type — The Rust Book (bahasa Inggris): mengembalikan slice
&stryang meminjam dari input, versi aman dari Perbaikan 2. Cow— dokumentasi standard library (bahasa Inggris): tipe clone-on-write dari Perbaikan 4, lengkap dengan contoh.