Error Rust E0428: the name is defined multiple times (nama didefinisikan dua kali)
E0428 artinya: kamu mendefinisikan dua hal dengan nama yang sama di tempat yang sama: dua fungsi bernama area, dua struct bernama User, atau sebuah enum dan sebuah struct yang sama-sama bernama Status. Ini sering terjadi saat kamu mencoba melakukan overloading pada sebuah fungsi, seperti yang biasa kamu lakukan di Java, C#, atau C++. Rust tidak punya overloading, tapi punya pengganti yang bagus, dan halaman ini menunjukkannya. (Halaman ini bagian dari Penjelasan error compiler Rust.)
Pesan error-nya
Section titled “Pesan error-nya”error[E0428]: the name `area` is defined multiple times --> src/main.rs:5:1 |1 | fn area(width: f64, height: f64) -> f64 { | --------------------------------------- previous definition of the value `area` here...5 | fn area(radius: f64) -> f64 { // ❌ `area` yang kedua | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `area` redefined here | = note: `area` must be defined only once in the value namespace of this moduleArtinya: nama area didefinisikan lebih dari sekali. rustc menunjukkan definisi pertama, lalu definisi kedua yang ditolak.
Ini program yang menghasilkan error tersebut:
fn area(width: f64, height: f64) -> f64 { width * height}
fn area(radius: f64) -> f64 { // ❌ `area` yang kedua 3.14159 * radius * radius}
fn main() { println!("{}", area(2.0, 3.0)); println!("{}", area(1.0));}rustc juga menampilkan error kedua untuk program ini: E0061, “this function takes 2 arguments but 1 argument was supplied” (fungsi ini menerima 2 argumen tapi hanya diberi 1), di area(1.0). Itu hanya efek samping. Rust menyimpan area yang pertama dan mengabaikan yang kedua, jadi pemanggilan dengan satu argumen tidak cocok lagi. Perbaiki E0428, dan E0061 ikut hilang.
Apa artinya
Section titled “Apa artinya”rustc menunjuk ke dua tempat:
- Baris
---(baris 1): “previous definition of the valueareahere” (definisi sebelumnya dari nilaiareaada di sini). Iniareayang pertama, yang disimpan oleh Rust. - Baris
^^^(baris 5): “arearedefined here” (areadidefinisikan ulang di sini). Ini yang kedua, dan yang inilah yang ditolak. note:-nya bilangareahanya boleh didefinisikan sekali “in the value namespace of this module” (di namespace nilai modul ini). Setiap modul ibarat satu laci, dan di dalam satu laci setiap nama harus unik.
Untuk dua struct, catatannya menyebut “type namespace” (namespace tipe). Rust menyimpan tipe (struct, enum, trait, modul) dan nilai (fungsi, konstanta, static) di dua daftar yang terpisah. Itulah sebabnya mod shapes dan fn shapes bisa hidup berdampingan, tapi dua fn area atau dua struct User tidak bisa.
Bayangkan dua file bernama report.txt di satu folder. Komputermu menolak file kedua, bukan karena ada yang salah dengan isinya, tapi karena nama report.txt tidak lagi bisa memberi tahu file mana yang kamu maksud.
Kenapa Rust melakukan ini
Section titled “Kenapa Rust melakukan ini”Di Rust, sebuah nama di dalam modul menunjuk ke tepat satu item. Saat kamu menulis area(...), Rust mencari fungsinya hanya berdasarkan namanya, bukan berdasarkan jumlah atau tipe argumennya. Ini membuat kode tetap mudah dibaca: hanya ada satu area yang perlu dicari, dan menambahkan fungsi baru tidak akan pernah diam-diam mengubah fungsi mana yang dipakai oleh pemanggilan lama.
Bahasa yang punya overloading memilih versinya dari argumen, dan aturannya jadi rumit begitu angka bisa dikonversi satu sama lain atau ada nilai default yang ikut campur. Rust memilih untuk tidak melakukannya. Kalau kamu ingin “nama yang sama untuk input yang berbeda”, kamu memakai trait atau generics, tempat pilihannya terlihat dari tipenya. Penjelasan lebih lanjut tentang fungsi ada di Fungsi.
Cara memperbaikinya
Section titled “Cara memperbaikinya”Perbaikan 1: Beri masing-masing nama sendiri
Section titled “Perbaikan 1: Beri masing-masing nama sendiri”Pilih ini hampir setiap saat. Dua fungsi yang menerima input berbeda biasanya mengerjakan tugas yang berbeda, dan namanya bisa menjelaskan yang mana. Kalau salah satunya adalah salinan lama yang lupa kamu hapus, hapus saja:
fn rectangle_area(width: f64, height: f64) -> f64 { width * height}
fn circle_area(radius: f64) -> f64 { 3.14159 * radius * radius}
fn main() { println!("{}", rectangle_area(2.0, 3.0)); println!("{}", circle_area(1.0));}Output:
63.14159Standard library juga melakukan hal yang sama: String::new(), String::with_capacity(10), dan String::from("hi") adalah tiga nama berbeda untuk tiga cara membuat String.
Perbaikan 2: Taruh di modul yang terpisah
Section titled “Perbaikan 2: Taruh di modul yang terpisah”Pilih ini kalau nama pendeknya memang yang paling cocok di setiap konteks, seperti area untuk setiap bentuk, atau User di kode database-mu dan User lain di kode API-mu. Setiap modul punya daftar namanya sendiri, jadi bentroknya hilang. Pemanggil menulis nama modulnya di depan:
mod rectangle { pub fn area(width: f64, height: f64) -> f64 { width * height }}
mod circle { pub fn area(radius: f64) -> f64 { 3.14159 * radius * radius }}
fn main() { println!("{}", rectangle::area(2.0, 3.0)); println!("{}", circle::area(1.0));}Output:
63.14159Jangan lupa pub, atau pemanggilan dari main memberi E0603, “function is private” (fungsinya private). Lihat Modul.
Perbaikan 3: Pakai trait sebagai pengganti overloading
Section titled “Perbaikan 3: Pakai trait sebagai pengganti overloading”Pilih ini kalau kamu ingin satu pemanggilan yang bekerja untuk banyak tipe, yang biasanya memang tujuan overloading. Buat satu tipe untuk setiap jenis input, dan beri mereka trait yang sama. Sekarang setiap bentuk punya area sendiri, dan Rust memilih yang tepat dari tipe nilainya:
trait Shape { fn area(&self) -> f64;}
struct Rectangle { width: f64, height: f64,}
struct Circle { radius: f64,}
impl Shape for Rectangle { fn area(&self) -> f64 { self.width * self.height }}
impl Shape for Circle { fn area(&self) -> f64 { 3.14159 * self.radius * self.radius }}
fn print_area<T: Shape>(shape: &T) { println!("Luas: {}", shape.area());}
fn main() { print_area(&Rectangle { width: 2.0, height: 3.0 }); print_area(&Circle { radius: 1.0 });}Output:
Luas: 6Luas: 3.14159Kodenya lebih banyak daripada Perbaikan 1, jadi ini sepadan kalau kamu punya beberapa bentuk atau beberapa fungsi (area, perimeter, draw) yang semuanya mengikuti pola yang sama. Fungsi generic print_area<T: Shape> bisa dipakai untuk bentuk apa pun yang kamu tambahkan nanti. Lihat Trait dan Generics.
Untuk “fungsi yang sama, dengan atau tanpa argumen tambahan”, ada pilihan yang lebih ringan: terima sebuah Option, seperti fn greet(name: &str, title: Option<&str>), lalu panggil dengan None atau Some("Dr.").
Perbaikan 4: Ganti nama import dengan use ... as ...
Section titled “Perbaikan 4: Ganti nama import dengan use ... as ...”Pilih ini kalau yang bentrok adalah item buatanmu sendiri dan sebuah baris use. Sebenarnya itu error saudaranya, E0255, dengan judul yang sama:
error[E0255]: the name `Error` is defined multiple times --> src/main.rs:3:1 |1 | use std::io::Error; | -------------- previous import of the type `Error` here2 |3 | enum Error { | ^^^^^^^^^^ `Error` redefined here | = note: `Error` must be defined only once in the type namespace of this modulehelp: you can use `as` to change the binding name of the import |1 | use std::io::Error as OtherError; | +++++++++++++Artinya: nama Error sudah di-import di baris 1, lalu didefinisikan ulang sebagai enum di baris 3. rustc menyarankan memakai as untuk mengganti nama import-nya.
Beri import itu nama panggilan lokal dengan as. Pilih nama yang menunjukkan asalnya, seperti IoError, daripada nama sementara dari rustc, OtherError:
use std::io::Error as IoError;use std::io::ErrorKind;
#[derive(Debug)]enum Error { NotFound(String), Invalid(u32),}
fn main() { let mine = Error::NotFound(String::from("config.toml")); let other = Error::Invalid(42); let disk = IoError::new(ErrorKind::Other, "disk penuh");
println!("{:?}", mine); println!("{:?}", other); println!("{}", disk);}Output:
NotFound("config.toml")Invalid(42)disk penuhDua baris use yang bentrok, seperti use std::fmt::Result; dan use std::io::Result;, memberi saudara ketiga, E0252 (`Result` reimported here, Result di-import ulang di sini). Perbaikannya sama: use std::io::Result as IoResult;, atau import modulnya (use std::io;) lalu tulis io::Result. Mengganti nama enum buatanmu sendiri (AppError) juga bisa.
Di mana biasanya kamu melihatnya
Section titled “Di mana biasanya kamu melihatnya”Overloading method di blok impl. Dua fn new di impl Timer memberi kode lain, E0592: duplicate definitions with name `new` (definisi ganda dengan nama new). Penyebabnya sama, perbaikannya juga sama: beri nama sesuai tugasnya, seperti Timer::new() dan Timer::with_seconds(30). Lihat Struct.
Copy-paste saat refactoring. Kamu menyalin sebuah fungsi untuk diubah, atau menempelkan struct User dari file lain, lalu lupa menghapus yang lama. Ini juga sering terjadi di test: dua #[test] fn it_works() di satu mod tests memberi E0428. Perbaikannya: hapus salinan lamanya, atau ganti nama test-nya.
Varian enum yang ganda. enum Color { Red, Red } juga memberi E0428, menunjuk ke Red yang kedua, dengan catatan “type namespace of this enum”. Perbaikannya: hapus atau ganti nama varian yang ganda. Lihat Enum.
Error terkait
Section titled “Error terkait”- E0061: jumlah argumen salah. Sering muncul tepat setelah E0428 saat kamu mencoba overloading sebuah fungsi.
- E0425: masalah kebalikannya: nama yang didefinisikan nol kali di tempat kamu memakainya.
- E0433: path seperti
circle::areayang bagian pertamanya (modulnya) tidak ditemukan. - E0034: dua trait memberi sebuah tipe method dengan nama yang sama; kamu harus menyebutkan yang mana yang kamu maksud.
- E0255 (sebuah
usebentrok dengan item lokal), E0252 (dua barisusebentrok), E0592 (method ganda di sebuahimpl): saudara-saudara yang ditunjukkan di atas. - Semua error compiler: daftar lengkap halaman error.
Kuis singkat
Section titled “Kuis singkat”Kuis singkat
1. Kamu menulis fn total(a: u32) dan fn total(a: u32, b: u32) di satu file. Apa yang terjadi?
2. Bisakah mod report dan fn report() berada di modul yang sama?
3. File-mu punya use std::fmt::Result; dan kamu mendefinisikan enum Result. Apa perbaikan yang rapi?
Skor: 0 / 3
Bacaan lebih lanjut
Section titled “Bacaan lebih lanjut”- E0428 — Rust error codes index (bahasa Inggris): penjelasan resmi, dengan contoh dua struct.
- Defining Modules to Control Scope and Privacy — The Rust Book (bahasa Inggris): bagaimana modul memberi setiap bagian kodemu daftar namanya sendiri.
- Providing New Names with the
asKeyword — The Rust Book (bahasa Inggris): contohfmt::Resultdanio::Result, diselesaikan denganas. - Traits — The Rust Book (bahasa Inggris): berbagi perilaku antartipe, jawaban Rust untuk overloading.
- Namespaces — The Rust Reference (bahasa Inggris): aturan persis untuk type namespace dan value namespace yang disebut di catatan error-nya.