Lewati ke konten

Error Rust E0252: the name is defined multiple times (dua import bentrok)

E0252 artinya: dua baris use memasukkan nama yang sama. Contoh buku teksnya adalah use std::fmt::Result; ditambah use std::io::Result;: dua tipe yang berbeda, sama-sama bernama Result. Contoh lainnya fmt::Error dan io::Error, atau dua trait Write. Error ini sangat umum dan mudah diperbaiki, biasanya cukup dengan mengubah satu atau dua baris use. rustc 1.97 masih melaporkannya dengan kodenya sendiri, E0252. (Halaman ini bagian dari Penjelasan error compiler Rust.)

error[E0252]: the name `Result` is defined multiple times
--> src/main.rs:2:5
|
1 | use std::fmt::Result;
| ---------------- previous import of the type `Result` here
2 | use std::io::Result; // ❌ `Result` yang kedua
| ^^^^^^^^^^^^^^^ `Result` reimported here
|
= note: `Result` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
2 | use std::io::Result as OtherResult; // ❌ `Result` yang kedua
| ++++++++++++++

Ini program yang menghasilkan error tersebut:

use std::fmt::Result;
use std::io::Result; // ❌ `Result` yang kedua
struct Temperature {
celsius: i32,
}
impl std::fmt::Display for Temperature {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result {
write!(f, "{} °C", self.celsius)
}
}
fn parse_temperature(text: &str) -> Result<Temperature> {
match text.trim().parse() {
Ok(celsius) => Ok(Temperature { celsius }),
Err(_) => Err(std::io::Error::other("bukan angka")),
}
}
fn main() {
match parse_temperature("21") {
Ok(t) => println!("{}", t),
Err(e) => println!("error: {}", e),
}
}

rustc menampilkan empat error lagi setelah yang ini: E0107 (“type alias takes 0 generic arguments”, type alias tidak menerima argumen generic), dua E0308 (tipe tidak cocok), dan sebuah E0277. Jangan kejar error-error itu. Rust menyimpan import yang pertama, jadi setiap Result di file ini sekarang berarti fmt::Result, dan parse_temperature jadi tidak masuk akal lagi. Perbaiki E0252, dan semuanya ikut hilang.

rustc menunjuk ke dua baris use:

  1. Baris --- (baris 1): “previous import of the type Result here” (import sebelumnya untuk tipe Result ada di sini). Baris ini datang lebih dulu, jadi inilah yang disimpan oleh Rust.
  2. Baris ^^^ (baris 2): “Result reimported here” (Result di-import ulang di sini). Import kedua mencoba memakai nama yang sama.
  3. help:-nya menyarankan mengganti nama import kedua dengan as.

std::fmt::Result dan std::io::Result memang berbeda. fmt::Result adalah Result<(), fmt::Error> biasa, dipakai oleh Display dan Debug. io::Result<T> adalah Result<T, io::Error>, dipakai untuk file dan jaringan. Namanya sama, tugasnya berbeda.

Ini seperti menyimpan dua kontak bernama “Ibu” di HP-mu: ibumu sendiri dan ibu pasanganmu. Saat kamu mengetuk “Ibu”, HP-nya harus tahu siapa yang mau ditelepon. Kamu menambahkan satu kata di salah satunya, atau menyimpannya sebagai “Ibu (Rina)” dan “Ibu (Sari)”.

Di dalam satu modul, setiap nama menunjuk ke tepat satu item. Baris use tidak menyalin apa pun; ia hanya menambahkan nama pendek untuk item yang tinggal di tempat lain. Dua baris use yang menambahkan nama pendek yang sama akan membuat setiap Result sesudahnya ambigu, jadi Rust berhenti di import-nya alih-alih menebak di setiap pemakaian.

E0252 adalah salah satu dari tiga saudara dengan judul yang sama: E0255 adalah baris use yang bentrok dengan item buatanmu sendiri, dan E0428 adalah dua item buatanmu sendiri. Aturan di balik ketiganya adalah “satu nama, satu hal, per modul”. Lihat Modul.

Perbaikan 1: Import modulnya, lalu tulis fmt:: dan io::

Section titled “Perbaikan 1: Import modulnya, lalu tulis fmt:: dan io::”

Pilih ini hampir setiap saat, dan selalu untuk Result dan Error. Import modul induknya, lalu tulis nama modulnya di depan. Sekarang setiap pemakaian menyebutkan Result yang mana. The Rust Book menyarankan gaya ini justru untuk kasus seperti ini:

use std::fmt;
use std::io;
struct Temperature {
celsius: i32,
}
impl fmt::Display for Temperature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} °C", self.celsius)
}
}
fn parse_temperature(text: &str) -> io::Result<Temperature> {
match text.trim().parse() {
Ok(celsius) => Ok(Temperature { celsius }),
Err(_) => Err(io::Error::other("bukan angka")),
}
}
fn main() {
for input in ["21", " -4 ", "hangat"] {
match parse_temperature(input) {
Ok(t) => println!("{}", t),
Err(e) => println!("error: {}", e),
}
}
}

Output:

21 °C
-4 °C
error: bukan angka
▶ Coba sendiri

Bonus: Result<T, E> biasa dari prelude tetap bebas dipakai, tanpa import apa pun.

Perbaikan 2: Ganti nama salah satu import dengan as

Section titled “Perbaikan 2: Ganti nama salah satu import dengan as”

Pilih ini kalau kamu sering sekali memakai salah satu dari dua tipe itu dan ingin nama pendek untuknya. Ini saran dari rustc. Pilih nama yang menunjukkan asalnya, seperti IoResult, daripada OtherResult:

use std::fmt::Result;
use std::io::Result as IoResult;
struct Temperature {
celsius: i32,
}
impl std::fmt::Display for Temperature {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result {
write!(f, "{} °C", self.celsius)
}
}
fn parse_temperature(text: &str) -> IoResult<Temperature> {
match text.trim().parse() {
Ok(celsius) => Ok(Temperature { celsius }),
Err(_) => Err(std::io::Error::other("bukan angka")),
}
}
fn main() {
match parse_temperature("21") {
Ok(t) => println!("{}", t),
Err(e) => println!("error: {}", e),
}
}

Output:

21 °C
▶ Coba sendiri

Result polos yang diam-diam berarti fmt::Result bisa mengejutkan pembaca berikutnya, jadi Perbaikan 1 biasanya lebih jelas. as paling berguna untuk nama yang panjang, seperti use std::collections::BTreeMap as Map;.

Pilih ini untuk trait yang kamu import hanya untuk memanggil method-nya. Dua trait Write adalah contoh klasiknya: fmt::Write membuatmu bisa write! ke dalam String, sedangkan io::Write membuatmu bisa write! ke stdout atau file. Meng-import keduanya dengan nama akan bentrok:

error[E0252]: the name `Write` is defined multiple times
--> src/main.rs:2:5
|
1 | use std::fmt::Write;
| --------------- previous import of the trait `Write` here
2 | use std::io::Write; // ❌ `Write` yang kedua
| ^^^^^^^^^^^^^^ `Write` reimported here
|
= note: `Write` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
2 | use std::io::Write as OtherWrite; // ❌ `Write` yang kedua
| +++++++++++++

Artinya sama seperti tadi: trait Write yang kedua di-import ulang di baris 2. Program yang rusak:

use std::fmt::Write;
use std::io::Write; // ❌ `Write` yang kedua
fn main() {
let mut report = String::new();
write!(report, "{} test lulus", 12).unwrap();
let mut out = std::io::stdout();
writeln!(out, "{}", report).unwrap();
}

Di sini kamu tidak pernah menulis Write sendiri; kamu hanya butuh method-nya. as _ meng-import sebuah trait tanpa memberinya nama, jadi tidak ada yang bisa bentrok, dan kedua kelompok method tetap jalan:

use std::fmt::Write as _;
use std::io::Write as _;
fn main() {
let mut report = String::new();
write!(report, "{} test lulus", 12).unwrap();
let mut out = std::io::stdout();
writeln!(out, "{}", report).unwrap();
}

Output:

12 test lulus
▶ Coba sendiri

Kalau kamu perlu menyebut nama salah satunya, misalnya di fn log(w: &mut impl io::Write), gabungkan cara ini dengan Perbaikan 1: use std::io; lalu tulis io::Write. Lihat Trait.

Perbaikan 4: Hapus import ganda untuk item yang sama

Section titled “Perbaikan 4: Hapus import ganda untuk item yang sama”

Pilih ini kalau kedua baris meng-import hal yang persis sama, yang sering terjadi setelah menggabungkan kode atau saat editor-mu menambahkan import yang sebenarnya sudah ada:

error[E0252]: the name `HashMap` is defined multiple times
--> src/main.rs:2:24
|
1 | use std::collections::HashMap;
| ------------------------- previous import of the type `HashMap` here
2 | use std::collections::{HashMap, HashSet}; // ❌ `HashMap` lagi
| ^^^^^^^--
| |
| `HashMap` reimported here
| help: remove unnecessary import

Artinya: HashMap yang sama di-import dua kali, dan rustc menyarankan menghapus import yang tidak perlu. Program yang rusak:

use std::collections::HashMap;
use std::collections::{HashMap, HashSet}; // ❌ `HashMap` lagi
fn main() {
let mut stock: HashMap<&str, u32> = HashMap::new();
stock.insert("apel", 3);
let mut sold_out: HashSet<&str> = HashSet::new();
sold_out.insert("pir");
println!("apel: {}, habis: {}", stock["apel"], sold_out.len());
}

Perhatikan bahwa help-nya berbeda: tidak ada as, hanya “remove unnecessary import” (hapus import yang tidak perlu). Sisakan satu baris:

use std::collections::{HashMap, HashSet};
fn main() {
let mut stock: HashMap<&str, u32> = HashMap::new();
stock.insert("apel", 3);
let mut sold_out: HashSet<&str> = HashSet::new();
sold_out.insert("pir");
println!("apel: {}, habis: {}", stock["apel"], sold_out.len());
}

Output:

apel: 3, habis: 1
▶ Coba sendiri

Lihat HashMap dan HashSet.

Error dari dua tempat. use std::fmt::Error; dan use std::io::Error;, atau use std::error::Error; di samping use anyhow::Error;. Perbaikannya: use std::io; lalu tulis io::Error, atau use anyhow::Error as AnyError;. Lihat anyhow dan thiserror.

Dua crate dengan nama tipe yang sama. use chrono::Duration; dan use std::time::Duration; adalah pasangan yang sering muncul di proyek yang mengolah tanggal. Perbaikannya: pertahankan satu nama pendek dan tulis modul untuk yang lain, seperti chrono::Duration. Lihat Tanggal dan Waktu.

Import glob. use std::fmt::*; ditambah use std::io::*; tidak memberi E0252 di baris use-nya. Masalahnya muncul belakangan, di Result pertama yang kamu pakai, sebagai error tanpa kode: error: `Result` is ambiguous (Result ambigu). Perbaikannya: import nama yang kamu butuhkan secara eksplisit, seperti di Perbaikan 1.

  • E0255: baris use bentrok dengan struct, enum, atau fungsi buatanmu sendiri yang bernama sama.
  • E0428: dua item buatanmu sendiri bernama sama, sering karena mencoba overloading sebuah fungsi.
  • E0432: import tidak ditemukan, saat baris use menunjuk ke sesuatu yang tidak ada.
  • E0034: dua trait di scope memberi sebuah tipe method dengan nama yang sama.
  • E0308: tipe tidak cocok, salah satu error lanjutan setelah bentrokan Result.
  • Semua error compiler: daftar lengkap halaman error.

Kuis singkat

1. Kamu butuh fmt::Result dan io::Result di file yang sama. Import mana yang biasanya jadi pilihan rapi?

2. Kamu butuh method dari std::fmt::Write dan std::io::Write, tapi tidak pernah menulis nama trait-nya sendiri. Apa yang berhasil?

3. rustc bilang HashMap is reimported here dan menyarankan remove unnecessary import. Apa yang terjadi?

Skor: 0 / 3