Lewati ke konten

Error Rust E0405: cannot find trait in this scope (trait tidak ditemukan)

E0405 artinya: kamu menyebut sebuah trait yang tidak bisa dilihat Rust dari tempat itu. Contoh klasiknya: kamu menulis impl Display for Point supaya struct-mu bisa dicetak, tapi kamu tidak pernah meng-import Display. Salah ketik pada nama trait, atau trait yang tinggal di modul lain, memberi error yang sama. Ini salah satu error yang paling gampang diperbaiki, karena rustc biasanya menampilkan baris use persis yang kamu butuhkan. Berbeda dengan E0412 (“cannot find type”), yang berubah menjadi E0425 di Rust 1.93, kode ini tidak berubah: rustc 1.97 masih menampilkan E0405 untuk trait. (Halaman ini bagian dari Penjelasan error compiler Rust.)

error[E0405]: cannot find trait `Display` in this scope
--> src/main.rs:6:6
|
6 | impl Display for Point { // ❌ `Display` tidak pernah di-import
| ^^^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use std::fmt::Display;
|

Ini program yang menghasilkan error tersebut:

struct Point {
x: i32,
y: i32,
}
impl Display for Point { // ❌ `Display` tidak pernah di-import
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let p = Point { x: 3, y: 4 };
println!("{}", p);
}

^^^^^^^ menunjuk ke Display di baris 6, dengan label “not found in this scope” (tidak ditemukan di scope ini). Rust sudah melihat setiap trait yang terlihat dari sana: yang kamu definisikan di modul ini, yang dimasukkan oleh baris use-mu, dan sekumpulan kecil trait di prelude. Tidak satu pun yang bernama Display.

help:-nya memberi tahu tempatnya: use std::fmt::Display;. Tanda 1 + berarti “tambahkan ini sebagai baris 1 yang baru”, di bagian paling atas file.

Kenapa Display tidak ada, padahal println! memakainya terus? Prelude, yaitu daftar nama yang didapat setiap file Rust secara gratis, berisi Clone, Iterator, From, Default, dan trait sehari-hari lainnya, tapi tidak berisi Display, Error, Hash, atau Write. Trait-trait itu tinggal di modulnya masing-masing (std::fmt, std::error, std::hash, std::io), dan kamu meng-import-nya saat ingin mengimplementasikannya.

Ini seperti resep yang bilang “pakai panci Display”. Si juru masak tahu panci-panci yang ada di atas kompor, tapi panci yang ini ada di dalam lemari, dan resepnya tidak pernah bilang lemari yang mana.

Rust tidak pernah mencari sebuah nama di seluruh standard library, atau di seluruh proyekmu. Ia hanya melihat apa yang ada di scope: item buatanmu, baris use-mu, dan prelude. Ini membuat nama tetap bisa diprediksi. Di std saja ada beberapa trait bernama Write dan Error, dan crate yang kamu tambahkan nanti bisa membawa lebih banyak lagi. Kalau Rust memilihkan salah satunya untukmu, menambahkan sebuah dependency bisa diam-diam mengubah arti kodemu.

Jadi kamu menyebutkan trait mana yang kamu maksud, sekali saja, di bagian atas file. Baris help-nya sudah melakukan pencarian untukmu dan menyarankan trait yang ditemukannya. Lihat Modul untuk cara kerja use, dan Trait yang Sering Dipakai untuk Display.

Perbaikan 1: Tambahkan baris use yang disarankan rustc

Section titled “Perbaikan 1: Tambahkan baris use yang disarankan rustc”

Pilih ini kalau help-nya bilang consider importing this trait (coba import trait ini), dan itu yang paling sering terjadi. Salin barisnya ke bagian atas file:

use std::fmt::Display;
struct Point {
x: i32,
y: i32,
}
impl Display for Point {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let p = Point { x: 3, y: 4 };
println!("{}", p);
println!("Ferris ada di {}", Point { x: -1, y: 7 });
}

Output:

(3, 4)
Ferris ada di (-1, 7)
▶ Coba sendiri

Kalau rustc menyarankan beberapa import, baca dulu sebelum memilih. Itu trait-trait berbeda yang kebetulan bernama sama, seperti std::fmt::Write dan std::io::Write.

Perbaikan 2: Import modulnya dan tulis fmt::Display

Section titled “Perbaikan 2: Import modulnya dan tulis fmt::Display”

Pilih ini kalau kamu sedang mengimplementasikan Display, karena bagaimanapun kamu butuh Formatter dan Result dari modul yang sama. Import std::fmt sekali dan tulis fmt:: di depan ketiganya. Inilah gaya yang paling sering kamu lihat di kode Rust sungguhan:

use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let p = Point { x: 3, y: 4 };
let label = p.to_string();
println!("{} punya {} karakter", label, label.len());
}

Output:

(3, 4) punya 6 karakter
▶ Coba sendiri

Mengimplementasikan Display juga memberimu .to_string() secara gratis. Kamu bisa melewatkan use sama sekali dan menulis impl std::fmt::Display for Point; itu tidak masalah untuk pemakaian sekali saja.

Perbaikan 3: Betulkan ejaan nama trait-nya

Section titled “Perbaikan 3: Betulkan ejaan nama trait-nya”

Pilih ini kalau rustc bilang a trait with a similar name exists (ada trait dengan nama yang mirip). Nama trait peka huruf besar-kecil, jadi shape, Shap, dan Shape adalah tiga nama yang berbeda:

error[E0405]: cannot find trait `Shap` in this scope
--> src/main.rs:9:6
|
1 | trait Shape {
| ----------- similarly named trait `Shape` defined here
...
9 | impl Shap for Square { // ❌ salah ketik: Shap
| ^^^^
|
help: a trait with a similar name exists
|
9 | impl Shape for Square { // ❌ salah ketik: Shap
| +

Artinya: trait Shap tidak ada, tapi ada trait bernama mirip, Shape, yang didefinisikan di baris 1. Program yang rusak:

trait Shape {
fn area(&self) -> f64;
}
struct Square {
side: f64,
}
impl Shap for Square { // ❌ salah ketik: Shap
fn area(&self) -> f64 {
self.side * self.side
}
}
fn main() {
let s = Square { side: 3.0 };
println!("{}", s.area());
}

Tanda + di bawah baris 9 menunjukkan huruf yang kurang. Tambahkan hurufnya:

trait Shape {
fn area(&self) -> f64;
}
struct Square {
side: f64,
}
impl Shape for Square {
fn area(&self) -> f64 {
self.side * self.side
}
}
fn main() {
let s = Square { side: 3.0 };
println!("{}", s.area());
}

Output:

9
▶ Coba sendiri

Kalau tidak ada nama yang mirip dan tidak ada saran import, berarti trait-nya memang belum ada. Definisikan dulu dengan trait Shape { ... }. Lihat Trait.

Perbaikan 4: Import trait buatanmu dari modulnya

Section titled “Perbaikan 4: Import trait buatanmu dari modulnya”

Pilih ini kalau trait-nya buatanmu sendiri tapi tinggal di modul lain. Setiap modul punya scope sendiri, jadi trait di mod shapes tidak terlihat di level atas main.rs sampai kamu meng-import-nya:

error[E0405]: cannot find trait `Shape` in this scope
--> src/main.rs:11:6
|
11 | impl Shape for Square { // ❌ `Shape` ada di `mod shapes`
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use crate::shapes::Shape;
|

Artinya: Shape tidak terlihat di baris 11, dan rustc menyarankan meng-import-nya dari crate::shapes. Program yang rusak:

mod shapes {
pub trait Shape {
fn area(&self) -> f64;
}
}
struct Square {
side: f64,
}
impl Shape for Square { // ❌ `Shape` ada di `mod shapes`
fn area(&self) -> f64 {
self.side * self.side
}
}
fn main() {
println!("{}", Square { side: 2.0 }.area());
}

Tambahkan baris use-nya, dan pastikan trait-nya pub. Tanpa pub, import-nya sendiri gagal dengan E0603, “trait is private” (trait-nya private):

mod shapes {
pub trait Shape {
fn area(&self) -> f64;
}
}
use crate::shapes::Shape;
struct Square {
side: f64,
}
impl Shape for Square {
fn area(&self) -> f64 {
self.side * self.side
}
}
fn main() {
println!("{}", Square { side: 2.0 }.area());
}

Output:

4
▶ Coba sendiri

Hal yang sama berlaku untuk trait dari crate: impl Serialize for User butuh use serde::Serialize; lebih dulu. Lihat Modul.

Box<dyn Error> di main atau di fungsi pembantu. fn run() -> Result<(), Box<dyn Error>> tanpa import memberi cannot find trait `Error` in this scope, dengan help: consider importing this trait, use std::error::Error;. Perbaikannya: tambahkan baris itu, atau tulis Box<dyn std::error::Error>. Lihat Error Kustom.

Trait bound pada generics. fn print_all<T: Display>(items: &[T]) memberi E0405 yang sama untuk Display, menunjuk ke bound-nya. Perbaikannya: use std::fmt::Display;. Lihat Generics.

Debug memberi kode yang berbeda. impl Debug for Point atau T: Debug tanpa import bukan E0405, melainkan E0404: expected trait, found derive macro `Debug` (yang diharapkan trait, yang ditemukan derive macro Debug). Prelude berisi makro #[derive(Debug)], tapi tidak berisi trait Debug. Perbaikannya: use std::fmt::Debug; (rustc menyarankannya), atau cukup #[derive(Debug)] kalau kamu tidak butuh format kustom.

  • E0425: tidak bisa menemukan nilai, fungsi, atau (sejak Rust 1.93) tipe di scope ini.
  • E0412: kode lama untuk “cannot find type”, sekarang dilaporkan sebagai E0425.
  • E0433: tidak bisa menemukan bagian pertama dari sebuah path, seperti fmt::Display tanpa use std::fmt;.
  • E0599: method tidak ditemukan, sering karena trait yang menyediakan method itu belum di-import.
  • E0277: trait-nya ditemukan, tapi tipemu tidak mengimplementasikannya.
  • E0404: nama yang ada, tapi bukan trait (seperti makro Debug), ditunjukkan di atas.
  • Semua error compiler: daftar lengkap halaman error.

Kuis singkat

1. Kamu menulis impl Display for Invoice dan mendapat E0405. Apa yang kurang?

2. Trait mana yang bisa kamu pakai tanpa baris use apa pun?

3. Trait Shape milikmu didefinisikan di mod shapes, dan impl Shape for Square ada di main.rs. Apa yang kamu butuhkan?

Skor: 0 / 3