Error Rust E0434: can't capture dynamic environment in a fn item (fn di dalam fn)
E0434 artinya: fungsi yang ditulis di dalam fungsi lain mencoba memakai salah satu variabel lokal fungsi luarnya. Kelihatannya seharusnya bisa: variabelnya ada di situ, beberapa baris di atasnya. Tapi fn bersarang di Rust adalah item yang terpisah, dan ia tidak bisa melihat variabel di sekitarnya. Istilah dari compiler, “dynamic environment” (lingkungan dinamis), sebenarnya cuma berarti “variabel lokal yang ada selama fungsi luarnya berjalan”. Ini salah satu error yang paling gampang diperbaiki: rustc sudah memberi jawabannya di baris help:. (Halaman ini bagian dari Penjelasan error compiler Rust.)
Pesan error-nya
Section titled “Pesan error-nya”error[E0434]: can't capture dynamic environment in a fn item --> src/main.rs:5:24 |5 | price * (1.0 + tax_rate) // ❌ inner `fn` can't see `tax_rate` | ^^^^^^^^ | = help: use the `|| { ... }` closure form insteadArtinya: item fn tidak bisa menangkap lingkungan dinamis (variabel lokal). Help-nya menyarankan memakai bentuk closure || { ... }.
Ini program yang menghasilkan error tersebut:
fn main() { let tax_rate = 0.2;
fn with_tax(price: f64) -> f64 { price * (1.0 + tax_rate) // ❌ inner `fn` can't see `tax_rate` }
println!("{:.2}", with_tax(10.0));}Apa artinya
Section titled “Apa artinya”Tanda ^^^ menunjuk ke tax_rate di baris 5. Itu variabel lokal milik main, dibuat dengan let di baris 2. Fungsi di dalamnya, with_tax, mencoba membacanya, dan itu tidak diizinkan.
Baris help: memberi perbaikannya: tulis sebuah closure, || { ... }, sebagai ganti fn bersarang. Closure bisa memakai variabel di sekitarnya. fn tidak bisa, di mana pun kamu menulisnya.
Sering kamu juga mendapat warning, unused variable: `tax_rate` (variabel tax_rate tidak dipakai), karena dari sudut pandang Rust tidak ada yang boleh memakainya. Warning itu ikut hilang bersama error-nya.
Ibaratnya surat bersegel yang kamu tulis di mejamu. Tidak penting bahwa catatanmu ada di meja saat kamu menulisnya; orang yang membukanya hanya melihat apa yang kamu masukkan ke dalam amplop.
Kenapa Rust melakukan ini
Section titled “Kenapa Rust melakukan ini”fn bersarang di-compile persis seperti fungsi di bagian atas file. Menulisnya di dalam main hanya menyembunyikan namanya dari bagian kode lainnya. Itu tidak menghubungkannya dengan variabel main, dan ada alasan bagus untuk itu: fungsi biasa tidak punya tempat untuk menyimpannya. Kamu bisa memanggil with_tax dari mana saja yang bisa dijangkau main, menyimpannya sebagai function pointer, atau memanggilnya setelah variabel main sudah tidak ada. fn biasa hanyalah kode, tanpa data yang menempel.
Closure adalah kode ditambah variabel yang ditangkapnya. Rust menyimpan nilai-nilai itu (atau referensinya) di dalam closure, dan borrow checker memastikan semuanya hidup cukup lama. Itulah sebabnya rustc mengarahkanmu ke closure. Lihat Menangkap variabel dari scope di sekitarnya.
Aturan yang sama berlaku untuk parameter generic: fn di dalam juga tidak bisa memakai T milik fungsi luarnya. Yang itu adalah E0401.
Cara memperbaikinya
Section titled “Cara memperbaikinya”Perbaikan 1: Pakai closure
Section titled “Perbaikan 1: Pakai closure”Pilih ini hampir setiap saat, kalau fungsi bantunya kecil dan hanya hidup di dalam satu fungsi. Tulis let nama = |params| isi;, dan closure itu bisa memakai variabel apa pun di scope:
fn main() { let tax_rate = 0.2;
let with_tax = |price: f64| price * (1.0 + tax_rate); // ✅ closure bisa melihat `tax_rate`
println!("{:.2}", with_tax(10.0)); println!("{:.2}", with_tax(24.5));
let prices = [3.0, 7.5, 12.0]; let total: f64 = prices.iter().map(|&p| with_tax(p)).sum(); println!("total: {:.2}", total);}Output:
12.0029.40total: 27.00Closure yang hanya membaca sebuah variabel akan meminjamnya, jadi kamu masih bisa memakai tax_rate sesudahnya. Kalau kamu mengubah variabel itu di dalam closure, closure-nya butuh let mut. Lihat Closure.
Perbaikan 2: Kirim nilainya sebagai argumen
Section titled “Perbaikan 2: Kirim nilainya sebagai argumen”Pilih ini kalau fungsi bantunya sebaiknya tetap menjadi fungsi sungguhan: lebih panjang, ingin kamu test, atau dipakai beberapa fungsi. Beri satu parameter lagi dan kirim nilainya:
fn with_tax(price: f64, tax_rate: f64) -> f64 { price * (1.0 + tax_rate) // ✅ `tax_rate` sekarang sebuah parameter}
fn receipt(prices: &[f64], tax_rate: f64) -> f64 { prices.iter().map(|&p| with_tax(p, tax_rate)).sum()}
fn main() { let tax_rate = 0.2; println!("{:.2}", with_tax(10.0, tax_rate)); println!("total: {:.2}", receipt(&[3.0, 7.5, 12.0], tax_rate));
let reduced_rate = 0.05; println!("{:.2}", with_tax(10.0, reduced_rate));}Output:
12.00total: 27.0010.50Di sini fungsinya pindah ke level teratas, tempat sebagian besar fungsi bantu Rust berada. Tetap bersarang juga bisa; yang penting nilainya masuk sebagai argumen. Bonusnya: sekarang fungsi ini bekerja untuk tarif pajak berapa pun, bukan cuma satu. Lihat Parameter.
Perbaikan 3: Jadikan const
Section titled “Perbaikan 3: Jadikan const”Pilih ini kalau nilainya tetap dan sudah diketahui sebelum program berjalan, seperti tarif pajak yang ditulis langsung di kode. Berbeda dengan variabel let, const adalah sebuah item, dan fungsi mana pun bisa memakainya, bersarang atau tidak:
const TAX_RATE: f64 = 0.2; // ✅ konstanta, terlihat oleh setiap fungsi
fn main() { fn with_tax(price: f64) -> f64 { price * (1.0 + TAX_RATE) }
println!("{:.2}", with_tax(10.0)); println!("{:.2}", with_tax(24.5));}Output:
12.0029.40Ini hanya bisa untuk nilai yang bisa dihitung saat compile. Kalau tarifnya berasal dari file, input pengguna, atau variabel lain, const tidak bisa dipakai: const RATE: f64 = tax_rate; memberi error lain, E0435 (attempt to use a non-constant value in a constant, mencoba memakai nilai non-konstan di dalam konstanta). Kalau begitu, pakai Perbaikan 1 atau Perbaikan 2. Lihat Konstanta.
Di mana biasanya kamu melihatnya
Section titled “Di mana biasanya kamu melihatnya”Kalau kamu datang dari JavaScript atau Python. Di bahasa-bahasa itu, fungsi bersarang bisa melihat variabel luarnya, jadi fn di dalam fn terasa wajar. Di Rust, yang bisa melakukan itu adalah closure. Perbaikannya: let helper = |x| ...; sebagai ganti fn helper(x) ....
Memakai self di fn bersarang di dalam method. fn report(&self) { fn show() { println!("{}", self.n); } } memberi E0434 yang sama, dengan tanda menunjuk ke self. Perbaikannya: jadikan show sebuah method (fn show(&self) di dalam impl) lalu panggil self.show(), atau pakai closure.
Parameter fungsi, bukan let. Di fn total(prices: &[f64], discount: f64), fn apply(price: f64) -> f64 { price - discount } yang bersarang juga memberi E0434: parameter juga termasuk variabel lokal. Perbaikannya: kirim discount ke apply, atau tulis let apply = |price: f64| price - discount;.
Error terkait
Section titled “Error terkait”- E0401: can’t use generic parameters from outer item: aturan yang sama untuk tipe:
fndi dalam tidak bisa memakaiTatauSelfmilik fungsi luarnya. - E0425: cannot find value in this scope: namanya sama sekali tidak ada, misalnya karena salah ketik, atau variabelnya milik fungsi lain.
- E0373: closure may outlive the current function: yang bisa kamu temui setelah beralih ke closure, kalau closure itu meminjam variabel dan hidup lebih lama darinya (perbaikannya:
move). - E0424:
selfis not available here:selfdipakai di fungsi yang bukan method. - E0435:
constyang mencoba memakai variabellet, ditunjukkan di Perbaikan 3. - Semua error compiler: daftar lengkap halaman error.
Kuis singkat
Section titled “Kuis singkat”Kuis singkat
1. Di dalam main, ada let limit = 10; dan fn check(n: i32) -> bool { n < limit } yang bersarang. Apa yang terjadi?
2. Versi mana yang bisa memakai variabel lokal limit?
3. Nilainya berasal dari input pengguna saat program berjalan. Perbaikan mana yang TIDAK akan berhasil?
Skor: 0 / 3
Bacaan lebih lanjut
Section titled “Bacaan lebih lanjut”- E0434 — Rust error codes index (bahasa Inggris): penjelasan resmi, dengan perbaikan memakai closure dan memakai
const/static. - Closures — The Rust Book (bahasa Inggris): bagaimana closure menangkap lingkungannya, hal yang tidak bisa dilakukan
fnbersarang. - Capturing — Rust by Example (bahasa Inggris): meminjam, meminjam secara mutable, dan memindahkan nilai ke dalam closure, dengan contoh-contoh kecil.
- Item declarations — The Rust Reference (bahasa Inggris): aturan bahwa item di dalam fungsi tidak bisa memakai parameter atau variabel lokal fungsi itu.
- Constants — The Rust Book (bahasa Inggris): beda
constdanlet, dan apa saja yang boleh ada di ekspresi konstanta.