Lewati ke konten

Error Rust E0107: wrong number of generic arguments (jumlah argumen generic salah)

E0107 artinya: jumlah tipe di dalam <...> tidak cocok dengan yang diharapkan tipe atau fungsinya. Result butuh dua (Result<T, E>), HashMap butuh dua (HashMap<K, V>), Option dan Vec butuh satu. Kurang satu atau lebih satu, dan rustc akan bilang sesuatu seperti enum takes 2 generic arguments but 1 generic argument was supplied (enum menerima 2 argumen generic tapi hanya 1 yang diberikan), dengan “struct”, “enum”, “type alias”, “function”, atau “method” di depannya. Ini salah satu error yang paling ramah: rustc memberi tahu kedua angkanya, dan perbaikannya adalah menambah atau menghapus sebuah tipe. Halaman ini bagian dari panduan error compiler.

error[E0107]: enum takes 2 generic arguments but 1 generic argument was supplied
--> src/main.rs:1:29
|
1 | fn parse_age(text: &str) -> Result<u32> { // ❌ `Result` butuh dua tipe
| ^^^^^^ --- supplied 1 generic argument
| |
| expected 2 generic arguments
|
help: add missing generic argument
|
1 | fn parse_age(text: &str) -> Result<u32, E> { // ❌ `Result` butuh dua tipe
| +++

Ini program yang menghasilkan error tersebut:

fn parse_age(text: &str) -> Result<u32> { // ❌ `Result` butuh dua tipe
text.trim().parse()
}
fn main() {
for input in ["42", "empat puluh"] {
match parse_age(input) {
Ok(age) => println!("umur: {}", age),
Err(e) => println!("error: {}", e),
}
}
}

rustc menunjuk ke baris 1 dua kali:

  1. Tanda ^^^^^^ di bawah Result: “expected 2 generic arguments” (diharapkan 2 argumen generic). Result adalah sebuah enum dengan dua parameter tipe: T untuk nilai kalau berhasil dan E untuk error-nya.
  2. Tanda --- di bawah u32: “supplied 1 generic argument” (diberikan 1 argumen generic). Kamu hanya memberi T.
  3. help:-nya menambahkan placeholder E. Itu petunjuk di mana tipenya harus ditulis, bukan tipenya sendiri: kamu mengganti E dengan tipe error yang sebenarnya.

Argumen generic itu seperti isian kosong di sebuah formulir. Formulir Result punya dua isian, “kalau berhasil:” dan “kalau gagal:”. Isi satu saja, dan petugasnya akan mengembalikan formulirmu.

Error ini sangat sering muncul kalau kamu pernah membaca kode yang menulis Result<u32> dengan satu tipe. Kode itu tidak salah: ia memakai type alias seperti io::Result<T> atau anyhow::Result<T>, yang mengisi tipe error-nya untukmu. Result biasa dari prelude tidak punya jalan pintas seperti itu.

Tipe generic belum menjadi tipe yang lengkap sampai setiap parameternya punya nilai. Result<u32, E> dengan E yang tidak diketahui tidak menjelaskan seberapa besar nilainya atau seperti apa bentuk error-nya, jadi Rust tidak bisa mengompilasi kode yang memakainya. Rust bisa saja mencoba menebak tipe yang hilang dari isi fungsinya, tapi ia sengaja tidak pernah menyimpulkan tipe di signature fungsi. Signature adalah kontrak yang diandalkan kode lain, jadi harus ditulis lengkap.

Sebagian parameter memang punya nilai default. HashMap<K, V, S = RandomState> punya parameter ketiga untuk hasher, itulah sebabnya rustc bilang “at least 2” (paling sedikit 2) untuk HashMap. Default hanya bisa mengisi dari belakang, dan hanya di tempat yang sudah diberi default oleh pembuat tipenya. Lihat Generics dan Result.

Pilih ini di sebagian besar kasus. Cari tahu seharusnya parameter yang kurang itu apa, lalu tulis. Untuk parse(), tipe error untuk angka yang gagal di-parse adalah std::num::ParseIntError:

use std::num::ParseIntError;
fn parse_age(text: &str) -> Result<u32, ParseIntError> {
text.trim().parse()
}
fn main() {
for input in ["42", "empat puluh"] {
match parse_age(input) {
Ok(age) => println!("umur: {}", age),
Err(e) => println!("error: {}", e),
}
}
}

Output:

umur: 42
error: invalid digit found in string
▶ Coba sendiri

Pesan invalid digit found in string (ada digit yang tidak valid di string) berasal dari standard library, jadi tetap dalam bahasa Inggris. Tidak yakin tipe error-nya apa? Cek dokumentasi fungsi yang error-nya kamu kembalikan. Perbaikan yang sama berlaku untuk HashMap<String>: sebutkan tipe nilainya, seperti HashMap<String, u32>. Lihat HashMap dan Error Kustom.

Perbaikan 2: Pakai alias satu tipe yang kamu maksud, seperti io::Result

Section titled “Perbaikan 2: Pakai alias satu tipe yang kamu maksud, seperti io::Result”

Pilih ini kalau kamu bekerja dengan file, jaringan, atau stdin, atau kalau kamu melihat Result<T> di kode orang lain. std::io::Result<T> adalah singkatan dari Result<T, std::io::Error>. Import modulnya dan tulis io::Result:

use std::fs;
use std::io;
fn read_config(path: &str) -> io::Result<String> {
fs::read_to_string(path)
}
fn main() {
match read_config("missing-config.toml") {
Ok(text) => println!("{}", text),
Err(e) => println!("gagal membaca config: {}", e),
}
}

Output:

gagal membaca config: No such file or directory (os error 2)
▶ Coba sendiri

Aplikasi yang memakai crate anyhow menulis anyhow::Result<T> dengan cara yang sama. Kesalahan kebalikannya juga E0107: io::Result<String, io::Error> memberi type alias takes 1 generic argument but 2 generic arguments were supplied, karena alias-nya sudah berisi tipe error. Hapus yang kedua. Lihat File I/O dan anyhow dan thiserror.

Perbaikan 3: Jadikan fungsimu generic, atau sebutkan tipenya

Section titled “Perbaikan 3: Jadikan fungsimu generic, atau sebutkan tipenya”

Pilih ini kalau tipenya adalah struct generic buatanmu sendiri dan kamu hanya menulis namanya. rustc bilang missing generics for struct `Pair` (generics untuk struct Pair tidak ada):

error[E0107]: missing generics for struct `Pair`
--> src/main.rs:6:13
|
6 | fn show(p: &Pair) { // ❌ `K` dan `V` yang mana?
| ^^^^ expected 2 generic arguments
|
note: struct defined here, with 2 generic parameters: `K`, `V`
--> src/main.rs:1:8
|
1 | struct Pair<K, V> {
| ^^^^ - -
help: add missing generic arguments
|
6 | fn show(p: &Pair<K, V>) { // ❌ `K` dan `V` yang mana?
| ++++++

Program yang rusak:

struct Pair<K, V> {
key: K,
value: V,
}
fn show(p: &Pair) { // ❌ `K` dan `V` yang mana?
println!("{} = {}", p.key, p.value);
}
fn main() {
show(&Pair { key: "volume", value: 7 });
show(&Pair { key: "tema", value: "gelap" });
}

help:-nya menulis Pair<K, V>, tapi K dan V belum ada di show, jadi kamu juga harus mendeklarasikannya. Karena show dipanggil dengan dua jenis Pair yang berbeda, jadikan fungsinya generic, dengan bound yang dibutuhkannya untuk mencetak:

use std::fmt::Display;
struct Pair<K, V> {
key: K,
value: V,
}
fn show<K: Display, V: Display>(p: &Pair<K, V>) {
println!("{} = {}", p.key, p.value);
}
fn main() {
show(&Pair { key: "volume", value: 7 });
show(&Pair { key: "tema", value: "gelap" });
}

Output:

volume = 7
tema = gelap
▶ Coba sendiri

Kalau fungsinya hanya pernah menangani satu jenis, sebutkan tipenya saja: fn show(p: &Pair<&str, u32>). Hal yang sama berlaku untuk impl Pair { ... }, yang harus ditulis impl<K, V> Pair<K, V> { ... }. Lihat Generics.

Pilih ini kalau rustc bilang “but 2 generic arguments were supplied” (tapi 2 argumen generic diberikan) dan menginginkan lebih sedikit. Ini sering terjadi dengan turbofish ::<> pada pemanggilan fungsi:

error[E0107]: function takes 1 generic argument but 2 generic arguments were supplied
--> src/main.rs:13:20
|
13 | println!("{}", largest::<i32, i32>(&scores)); // ❌ kelebihan satu tipe
| ^^^^^^^ ----- help: remove the unnecessary generic argument
| |
| expected 1 generic argument
|
note: function defined here, with 1 generic parameter: `T`
--> src/main.rs:1:4
|
1 | fn largest<T: PartialOrd + Copy>(items: &[T]) -> T {
| ^^^^^^^ -

Program yang rusak:

fn largest<T: PartialOrd + Copy>(items: &[T]) -> T {
let mut best = items[0];
for &item in items {
if item > best {
best = item;
}
}
best
}
fn main() {
let scores = [72, 95, 88];
println!("{}", largest::<i32, i32>(&scores)); // ❌ kelebihan satu tipe
}

largest punya satu parameter, T, jadi ia menerima satu tipe. Tulis largest::<i32>(...), atau buang turbofish-nya sama sekali, karena Rust bisa menyimpulkan T dari argumennya:

fn largest<T: PartialOrd + Copy>(items: &[T]) -> T {
let mut best = items[0];
for &item in items {
if item > best {
best = item;
}
}
best
}
fn main() {
let scores = [72, 95, 88];
println!("{}", largest(&scores));
println!("{}", largest::<f64>(&[1.5, 0.5]));
}

Output:

95
1.5
▶ Coba sendiri

note: adalah baris yang paling berguna di sini: ia menunjukkan definisinya dan menyebutkan parameternya, jadi kamu bisa menghitungnya sendiri.

HashMap<String> dengan key saja. rustc bilang struct takes at least 2 generic arguments but 1 generic argument was supplied. Perbaikannya: HashMap<String, u32>, atau tulis HashMap::new() dan biarkan Rust menyimpulkan keduanya dari insert pertama. Lihat HashMap.

Struct buatanmu dengan dua parameter tipe, tapi diberi satu. let p: Pair<&str> = ... memberi struct takes 2 generic arguments but 1 generic argument was supplied. Perbaikannya: Pair<&str, i32>, atau Pair<_, _> supaya Rust mengisi keduanya. Option<i32, i32> adalah kebalikannya: enum takes 1 generic argument but 2 generic arguments were supplied. Kalau kamu ingin dua nilai, pakai tuple, Option<(i32, i32)>.

Lifetime juga dihitung. Struct Excerpt<'a> yang ditulis sebagai Excerpt<'a, 'a> memberi struct takes 1 lifetime argument but 2 lifetime arguments were supplied. Perbaikannya: satu lifetime untuk setiap parameter di definisinya. Lihat Lifetime. Method yang sama sekali tidak generic, seperti .into::<String>(), memberi method takes 0 generic arguments but 1 generic argument was supplied; tulis let s: String = x.into(); sebagai gantinya (lihat E0283).

Satu hal yang mengejutkan: Vec<i32, i32> bukan E0107. Vec punya parameter kedua yang masih unstable untuk alokator memori, jadi kamu malah mendapat E0658 (allocator_api, bahasa Inggris) dan beberapa error lain. Perbaikannya sama: Vec<i32>, atau Vec<(i32, i32)> untuk pasangan nilai.

  • E0061: kesalahan yang sama dengan argumen biasa, fungsi yang menerima N argumen tapi diberi M.
  • E0106: lifetime specifier tidak ada, saat sebuah referensi di dalam tipe butuh 'a.
  • E0252: dua baris use meng-import nama yang sama; E0107 sering menyusul kalau Result ternyata berarti fmt::Result.
  • E0283: butuh anotasi tipe, perbaikan yang tepat saat .into::<T>() memberi E0107.
  • E0401: fungsi di dalam memakai T generic milik fungsi luarnya.
  • Semua error compiler: daftar lengkap halaman error.

Kuis singkat

1. fn load() -> Result<String> memberi E0107. Tipe kembalian mana yang memperbaikinya untuk fungsi yang membaca file?

2. Kenapa rustc bilang at least 2 generic arguments untuk HashMap?

3. fn show(p: &Pair) memberi `missing generics for struct Pair , dan show dipanggil dengan berbagai jenis Pair`. Apa perbaikannya?

Skor: 0 / 3