Lewati ke konten

Error Rust E0435: attempt to use a non-constant value in a constant (nilai non-konstan)

E0435 artinya: sesuatu yang harus sudah diketahui saat programmu di-compile mencoba memakai nilai yang baru ada saat program berjalan. Tempat yang paling sering adalah panjang array, seperti [0.0; days], atau sebuah const yang membaca variabel let. Kodenya kelihatan wajar sekali, dan di banyak bahasa lain kode seperti itu jalan. Di Rust, konstanta dan panjang array dihitung oleh compiler, sebelum program dimulai, jadi keduanya tidak bisa melihat variabel biasa. Error ini sangat umum, dan perbaikannya biasanya cuma satu kata. (Halaman ini bagian dari Penjelasan error compiler Rust.)

error[E0435]: attempt to use a non-constant value in a constant
--> src/main.rs:3:26
|
3 | let rainfall = [0.0; days]; // ❌ an array's length must be known at compile time
| ^^^^ non-constant value
|
help: consider using `const` instead of `let`
|
2 - let days = 7;
2 + const days: /* Type */ = 7;
|

Artinya: ada percobaan memakai nilai non-konstan di dalam konstanta, dan rustc menyarankan memakai const alih-alih let.

Ini program yang menghasilkan error tersebut:

fn main() {
let days = 7;
let rainfall = [0.0; days]; // ❌ an array's length must be known at compile time
println!("{:?}", rainfall);
}

Tanda ^^^^ menunjuk ke days di baris 3, di dalam [0.0; days]. Itu bentuk “ulang” sebuah array: tujuh salinan 0.0. Bagian setelah ; adalah panjang array, dan panjang itu bagian dari tipe array-nya: [f64; 7] dan [f64; 8] adalah dua tipe yang berbeda. Jadi rustc harus tahu angkanya saat meng-compile.

Tapi days adalah variabel let. Bagi rustc, let adalah nilai yang hanya ada saat program berjalan, bahkan kalau kamu menulis 7 biasa di sebelahnya. “Non-constant value” (nilai non-konstan) artinya persis itu.

Baris help: menunjukkan perbaikannya: ubah baris 2 menjadi const. Perhatikan placeholder /* Type */: sebuah const selalu butuh tipe yang ditulis, jadi kamu akan menulis const DAYS: usize = 7;.

Judul error yang sama muncul kalau sebuah const atau static membaca variabel let, seperti const PRICE_WITH_TAX: f64 = base_price * 1.2;. Kali ini help:-nya menyarankan arah sebaliknya: pakai let alih-alih const.

Ibaratnya mencetak formulir. Jumlah kotak di formulir ditentukan di percetakan, sebelum ada yang mengisinya. Kamu tidak bisa membuat jumlah kotaknya bergantung pada jawaban yang nanti ditulis seseorang di formulir itu.

Rust punya dua momen: compile time (waktu kompilasi), saat cargo build mengubah kodemu menjadi program, dan runtime (waktu berjalan), saat program dijalankan. const, static, dan panjang array semuanya ditentukan saat compile time. Compiler menuliskannya langsung ke dalam program. Itulah sebabnya semuanya cepat dan bisa dipakai di mana saja.

Variabel let milik runtime. Nilainya bisa datang dari file, dari input pengguna, atau dari perhitungan yang baru terjadi saat kodenya berjalan. Rust tidak membuat pengecualian untuk let days = 7; hanya karena kebetulan isinya literal: aturannya tetap sederhana, dan kodemu tidak tiba-tiba rusak saat suatu hari kamu mengganti 7 dengan read_days_from_config().

Jadi pertanyaan yang perlu kamu ajukan: apakah aku sudah tahu angka ini saat menulis kodenya? Kalau ya, jadikan const. Kalau tidak, angka itu tidak bisa jadi panjang array, dan Vec adalah alat yang tepat. Lihat Konstanta dan Array vs vektor.

Pilih ini kalau angkanya tetap di kodemu, seperti 7 hari dalam seminggu. Lakukan apa yang dikatakan help:, dengan dua perubahan kecil: tulis tipenya (usize untuk panjang) dan pakai nama UPPER_CASE, gaya Rust untuk konstanta:

const DAYS: usize = 7; // ✅ sudah diketahui saat compile time
fn main() {
let mut rainfall = [0.0; DAYS];
rainfall[2] = 4.5;
rainfall[5] = 1.0;
println!("{:?}", rainfall);
println!("{} hari", rainfall.len());
}

Output:

[0.0, 0.0, 4.5, 0.0, 0.0, 1.0, 0.0]
7 hari
▶ Coba sendiri

Kamu juga bisa menaruh const-nya di dalam main, tepat di tempat let tadi. Kalau di bagian atas file, semua fungsi bisa memakainya. Kalau kamu tetap memakai nama huruf kecil days, kodenya tetap ter-compile, tapi dengan warning bahwa konstanta seharusnya ditulis dengan huruf besar.

Perbaikan 2: Pakai Vec kalau ukurannya baru diketahui saat runtime

Section titled “Perbaikan 2: Pakai Vec kalau ukurannya baru diketahui saat runtime”

Pilih ini kalau angkanya datang dari program yang sedang berjalan: panjang sebuah daftar, nilai dari file, input pengguna, parameter fungsi. Array punya ukuran tetap; Vec (vektor) adalah daftar yang bisa bertambah dan boleh berukuran berapa saja. vec![value; n] adalah bentuk “ulang” yang sama, dan di sini n boleh variabel apa pun:

fn main() {
let players = ["Ana", "Ben", "Chen"];
let rounds = players.len() * 2;
let mut scores = vec![0; rounds]; // ✅ panjang Vec boleh berasal dari variabel
scores[0] = 10;
scores[3] = 7;
println!("{:?}", scores);
println!("{} ronde", scores.len());
}

Output:

[10, 0, 0, 7, 0, 0]
6 ronde
▶ Coba sendiri

Perbaikan ini jauh lebih sering tepat daripada yang orang kira. Vec bisa dipakai hampir di mana pun array bisa dipakai: indexing, .len(), perulangan, slice (&scores[1..3]). Beda kecepatannya sangat kecil untuk program biasa. Lihat Vektor.

Pilih ini kalau sebuah const (atau static) membaca variabel let. Versi error-nya seperti ini:

error[E0435]: attempt to use a non-constant value in a constant
--> src/main.rs:3:33
|
3 | const PRICE_WITH_TAX: f64 = base_price * 1.2; // ❌ a `const` can't read a `let` variable
| ^^^^^^^^^^ non-constant value
|
help: consider using `let` instead of `const`

Artinya: base_price adalah nilai non-konstan, dan rustc menyarankan memakai let alih-alih const. Program yang rusak:

fn main() {
let base_price = 20.0;
const PRICE_WITH_TAX: f64 = base_price * 1.2; // ❌ a `const` can't read a `let` variable
println!("{:.2}", PRICE_WITH_TAX);
}

Kalau nilainya dihitung saat program berjalan, itu variabel biasa, jadi jadikan let (dengan nama huruf kecil). Kalau kedua nilai memang tetap, arah sebaliknya juga bisa: jadikan yang pertama const juga. Keduanya ditunjukkan di sini:

const BASE_PRICE: f64 = 20.0;
const PRICE_WITH_TAX: f64 = BASE_PRICE * 1.2; // ✅ const boleh memakai const lain
fn main() {
let base_price = 35.0;
let price_with_tax = base_price * 1.2; // ✅ let boleh memakai apa saja
println!("{:.2}", price_with_tax);
println!("{:.2}", PRICE_WITH_TAX);
}

Output:

42.00
24.00
▶ Coba sendiri

Baris help: menyarankan let PRICE_WITH_TAX; itu ter-compile, tapi kamu akan mendapat warning bahwa nama variabel seharusnya snake_case. Ganti namanya menjadi price_with_tax.

Perbaikan 4: Const generics atau const fn, kalau kamu benar-benar butuh array

Section titled “Perbaikan 4: Const generics atau const fn, kalau kamu benar-benar butuh array”

Pilih ini kalau kamu ingin array berukuran tetap yang sungguhan, tapi ukurannya harus datang dari luar sebuah fungsi, atau harus dihitung. Parameter fungsi juga nilai runtime, jadi ini memberi E0435 (rustc bilang parameternya would need to be a const, yaitu seharusnya berupa const):

error[E0435]: attempt to use a non-constant value in a constant
--> src/main.rs:2:21
|
1 | fn empty_row(size: usize) {
| ---- this would need to be a `const`
2 | let row = [0u8; size]; // ❌ `size` is only known when the function runs
| ^^^^

Program yang rusak:

fn empty_row(size: usize) {
let row = [0u8; size]; // ❌ `size` is only known when the function runs
println!("{:?}", row);
}
fn main() {
empty_row(3);
}

Const generic melakukan apa yang diminta rustc: <const N: usize> menjadikan ukurannya parameter compile time, ditulis empty_row::<5>() atau disimpulkan dari tipenya. const fn adalah fungsi yang bisa dijalankan compiler saat compile time, jadi kamu bisa memakainya untuk menghitung sebuah konstanta:

fn empty_row<const N: usize>() -> [u8; N] {
[0; N] // ✅ N adalah parameter compile time
}
const fn cells(width: usize, height: usize) -> usize {
width * height
}
const WIDTH: usize = 4;
const HEIGHT: usize = 3;
const CELLS: usize = cells(WIDTH, HEIGHT); // ✅ dihitung oleh compiler
fn main() {
let row: [u8; 3] = empty_row();
let wide = empty_row::<5>();
println!("{:?}", row);
println!("{:?}", wide);
let board = [0u8; CELLS];
println!("{} sel", board.len());
}

Output:

[0, 0, 0]
[0, 0, 0, 0, 0]
12 sel
▶ Coba sendiri

Satu batasan di Rust stable: di dalam fungsi generic kamu bisa memakai N begitu saja sebagai panjang, tapi tidak perhitungan dengannya, seperti [u8; N * 2]. Itu memberi generic parameters may not be used in const operations dan butuh fitur yang hanya ada di nightly. Kalau kamulah yang memanggil empty_row(size) dengan size dari runtime, kembali ke Perbaikan 2. Lihat Generics.

Ukuran dari .len() atau input pengguna. let n = names.len(); let done = [false; n]; memberi E0435, karena n baru diketahui saat runtime. Perbaikannya: let done = vec![false; n]; (Perbaikan 2).

static yang membaca let. static LINE_WIDTH: usize = width; memberi judul error yang sama, dengan help: consider using `let` instead of `static` . static ditentukan saat compile time, sama seperti const. Perbaikannya: pakai let, atau jadikan width sebuah const juga.

const di dalam fungsi generic. Di fn bytes<T>() -> usize { const SIZE: usize = std::mem::size_of::<T>(); SIZE }, const-nya tidak bisa memakai T. Itu kode yang berbeda, E0401, dan perbaikannya idenya sama: let size = std::mem::size_of::<T>();.

Kuis singkat

1. Kenapa let n = 3; let a = [0; n]; memberi E0435, padahal n jelas bernilai 3?

2. Ukuran daftarmu berasal dari file yang dibaca program. Apa perbaikan yang tepat?

3. Baris mana yang bisa ter-compile?

Skor: 0 / 3