Lewati ke konten

Error Rust E0689: can't call method on ambiguous numeric type (tipe angka ambigu)

E0689 artinya: kamu memanggil method pada sebuah angka, tapi Rust belum tahu angka itu jenisnya apa. 2 bisa berupa i32, u8, u64, dan lainnya, dan masing-masing punya method pow sendiri. Kamu cukup memberi tahu Rust mana yang kamu maksud, biasanya dengan beberapa karakter tambahan seperti 2_i32 atau let x: f64. rustc bahkan menunjukkan di mana kamu harus menaruhnya. (Halaman ini bagian dari Penjelasan error compiler Rust.)

error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
--> src/main.rs:2:16
|
2 | let kb = 2.pow(10); // ❌ `2` ini integer jenis apa?
| ^^^
|
help: you must specify a concrete type for this numeric value, like `i32`
|
2 | let kb = 2_i32.pow(10); // ❌ `2` ini integer jenis apa?
| ++++

Artinya: method pow tidak bisa dipanggil pada tipe angka yang masih ambigu, {integer}. rustc menyarankan untuk menyebut tipe yang konkret, misalnya i32.

Ini program yang menghasilkan error tersebut:

fn main() {
let kb = 2.pow(10); // ❌ `2` ini integer jenis apa?
println!("{}", kb);
}

Hal yang sama terjadi pada bilangan desimal. Di sini angkanya disimpan dulu di sebuah variabel, jadi rustc menyarankan tipe untuk variabelnya:

error[E0689]: can't call method `sqrt` on ambiguous numeric type `{float}`
--> src/main.rs:3:18
|
3 | let root = x.sqrt(); // ❌ `x` ini f32 atau f64?
| ^^^^
|
help: you must specify a type for this binding, like `f32`
|
2 | let x: f32 = 2.0;
| +++++

Artinya: sqrt tidak bisa dipanggil pada {float} yang ambigu, dan rustc menyarankan memberi tipe pada variabel x, misalnya f32.

fn main() {
let x = 2.0;
let root = x.sqrt(); // ❌ `x` ini f32 atau f64?
println!("{}", root);
}

{integer} dan {float} adalah cara rustc bilang “sebuah angka yang tipe pastinya belum kupilih”. {integer} adalah salah satu tipe bilangan bulat (i8 sampai i128, u8 sampai u128, isize, usize). {float} adalah f32 atau f64.

Tanda ^^^ menunjuk ke nama method-nya. Sebuah method dimiliki oleh sebuah tipe: ada i32::pow, u64::pow, f32::sqrt, f64::sqrt, dan seterusnya. Hasilnya berbeda-beda (i32 tidak muat untuk 2 pangkat 40, sedangkan u64 muat). Untuk memanggil salah satunya, Rust harus tahu tipenya di titik itu dalam kode, dan di sini Rust belum tahu.

Ini seperti bertanya ke pelayan toko “berapa harganya 2?”. Dua apa? Dua apel dan dua TV harganya jauh berbeda. Begitu kamu bilang “2 apel”, jawabannya gampang.

Rust memang punya tipe angka default. Kalau tidak ada hal lain yang menentukan, bilangan bulat menjadi i32 dan bilangan desimal menjadi f64. Lihat Integer (bilangan bulat) dan Floating-point (bilangan desimal).

Tapi default itu adalah pilihan terakhir. Rust membaca dulu sisa fungsinya untuk melihat apakah ada yang menentukan tipenya, misalnya angka itu dikirim ke fungsi yang menerima u8. Baru di akhir sekali Rust memakai i32 atau f64. Pemanggilan method tidak bisa menunggu selama itu: Rust perlu tahu pow yang mana yang dipanggil sebelum bisa memeriksa argumen dan tipe hasilnya. Jadi daripada menebak, Rust berhenti dan bertanya padamu.

Ini juga berarti kode yang datang belakangan tidak membantu. Bahkan let y: u64 = x.pow(10); tetap memberi E0689, karena Rust harus memilih tipe x sebelum memanggil pow, sedangkan u64 itu hanya ada di hasilnya. Yang membantu adalah memberi tipe pada angkanya sebelum pemanggilan method.

Perbaikan 1: Tambahkan sufiks tipe pada angkanya

Section titled “Perbaikan 1: Tambahkan sufiks tipe pada angkanya”

Pilih ini kalau kamu memanggil method langsung pada sebuah literal, seperti 2.pow(10) atau 2.0.sqrt(). Tulis tipenya tepat setelah angkanya. Tanda _ boleh tidak dipakai, gunanya hanya supaya mudah dibaca: 2_i32 dan 2i32 sama saja.

Untuk bilangan desimal, rustc menyarankan f32, tapi f64 adalah default Rust dan lebih presisi. Pilih f64, kecuali kamu punya alasan untuk menghemat memori.

fn main() {
let kb = 2_i32.pow(10); // ✅ sebuah i32
let big = 2_u64.pow(40); // ✅ sebuah u64: 2^40 tidak muat di i32
let root = 2.0_f64.sqrt(); // ✅ sebuah f64
let dist = (-7_i32).abs(); // ✅ pakai tanda kurung, karena `-` datang sebelum pemanggilan method
println!("2^10 = {}", kb);
println!("2^40 = {}", big);
println!("sqrt(2) = {}", root);
println!("|-7| = {}", dist);
}

Output:

2^10 = 1024
2^40 = 1099511627776
sqrt(2) = 1.4142135623730951
|-7| = 7
▶ Coba sendiri

Pilih tipe yang cukup besar untuk hasilnya. 2_i32.pow(40) bisa di-compile, tapi hasilnya overflow dan menyebabkan panic di build debug. Lihat Integer overflow.

Pilih ini kalau angkanya disimpan dulu di sebuah variabel, seperti let x = 2.0;. Inilah yang disarankan baris help: dari rustc. Tambahkan : tipe setelah nama variabelnya:

fn main() {
let x: f64 = 2.0; // ✅ sekarang x adalah f64
println!("{:.3}", x.sqrt());
let side: f64 = 3.5;
println!("luas = {}", side.powi(2));
let temperature: i32 = -5;
println!("{} derajat dari nol", temperature.abs());
let base: u64 = 2;
let y = base.pow(10); // y juga u64
println!("{}", y);
}

Output:

1.414
luas = 12.25
5 derajat dari nol
1024
▶ Coba sendiri

Sufiks pada nilainya juga sama bagusnya: let x = 2.0_f64;. Pakai yang menurutmu lebih mudah dibaca. Lihat Anotasi tipe.

Perbaikan 3: Beri tipe pada variabel loop atau argumen closure

Section titled “Perbaikan 3: Beri tipe pada variabel loop atau argumen closure”

Pilih ini kalau angkanya berasal dari sebuah range, seperti for i in 1..=3 atau (1..=5).map(|n| ...). Variabel i atau n bertipe {integer}, dan tidak ada let yang bisa diberi anotasi. rustc menunjuk ke variabelnya:

error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
--> src/main.rs:3:26
|
2 | for i in 1..=3 {
| - you must specify a type for this binding, like `i32`
3 | println!("{}", i.pow(2));
| ^^^

Artinya: rustc meminta kamu memberi tipe pada variabel i, misalnya i32.

Taruh sufiksnya di salah satu ujung range, atau beri tipe pada argumen closure-nya:

fn main() {
for i in 1..=3_u32 { // ✅ seluruh range sekarang bertipe u32
println!("{} kuadrat adalah {}", i, i.pow(2));
}
// bisa dengan sufiks pada range...
let total: u32 = (1..=5_u32).map(|n| n.pow(2)).sum();
// ...atau dengan tipe pada argumen closure
let total2: u32 = (1..=5).map(|n: u32| n.pow(2)).sum();
println!("jumlah kuadrat: {} dan {}", total, total2);
}

Output:

1 kuadrat adalah 1
2 kuadrat adalah 4
3 kuadrat adalah 9
jumlah kuadrat: 55 dan 55
▶ Coba sendiri

Perhatikan bahwa let total: u32 = ... saja tidak cukup: rustc butuh tipe n di dalam closure, sebelum sampai ke .sum(). Satu sufiks pada range sudah membereskan semuanya.

abs() pada angka negatif. let x = -5; x.abs() memberi can't call method `abs` on ambiguous numeric type `{integer}`. Perbaikannya: let x: i32 = -5;. Hati-hati dengan sufiks pada literalnya: -5_i32.abs() berarti -(5_i32.abs()), yang hasilnya -5. Pakai tanda kurung: (-5_i32).abs().

Hitungan cepat di main atau di test. let area = 3.14 * r * r; berjalan lancar, karena * adalah operator, bukan method. Error-nya baru muncul begitu kamu memanggil method seperti .sqrt(), .round(), atau .powi(). Perbaikannya: let r: f64 = 2.0;.

Vec berisi angka. Dengan let nums = vec![1, 2, 3];, nums.iter().map(|n| n.pow(2)) memberi kode lain, E0599, no method named `pow` found for reference `&{integer}`, karena di sini n adalah referensi. Perbaikannya sama: vec![1_i32, 2, 3] atau let nums: Vec<i32> = vec![1, 2, 3];.

Kuis singkat

1. Baris mana yang bisa di-compile?

2. Kalau tidak ada hal lain yang menentukan, tipe apa yang diberikan Rust untuk 7 dan 7.0?

3. for i in 0..10 { println!("{}", i.pow(2)); } memberi E0689. Apa perbaikan paling sederhana?

Skor: 0 / 3