Lewati ke konten

Error Rust E0411: cannot find type Self in this scope (Self di luar impl)

E0411 artinya: kamu menulis Self di tempat yang membuat Rust tidak tahu apa yang dimaksud. Self adalah singkatan untuk “tipe yang sedang dibahas blok impl (atau trait) ini”, jadi ia hanya bisa dipakai di dalam impl, trait, atau definisi tipe. Penyebab yang paling umum adalah constructor seperti fn new() -> Self yang ditulis di level atas file, atau method yang kamu salin keluar dari blok impl-nya. Error ini sering muncul dan cepat diperbaiki. Berbeda dengan E0412, yang berubah menjadi E0425 di Rust 1.93, kode ini tidak berubah: rustc 1.97 masih menampilkan E0411. (Halaman ini bagian dari Penjelasan error compiler Rust.)

error[E0411]: cannot find type `Self` in this scope
--> src/main.rs:5:21
|
5 | fn new_counter() -> Self { // ❌ `Self` di luar `impl`
| ----------- ^^^^ `Self` is only available in impls, traits, and type definitions
| |
| `Self` not allowed in a function

Ini program yang menghasilkan error tersebut:

struct Counter {
count: u32,
}
fn new_counter() -> Self { // ❌ `Self` di luar `impl`
Counter { count: 0 }
}
fn main() {
let c = new_counter();
println!("{}", c.count);
}

rustc menunjuk ke dua hal di baris 5:

  1. ^^^^ di bawah Self: “Self is only available in impls, traits, and type definitions” (Self hanya tersedia di impl, trait, dan definisi tipe). Itulah aturannya, dalam satu baris.
  2. ----- di bawah new_counter: “Self not allowed in a function” (Self tidak boleh dipakai di fungsi). Inilah alasannya di sini: new_counter adalah fungsi biasa, bukan bagian dari impl mana pun.

Kamu mungkin tahu bahwa new_counter mengembalikan Counter, karena kamu baru saja menulis Counter { count: 0 }. Tapi Rust tidak membaca isi fungsi untuk menebak arti Self. Self mendapat artinya hanya dari impl Counter { ... } atau trait ... { ... } yang membungkusnya, dan di sini tidak ada.

Ini seperti kata “di sini” pada selembar kertas tempel. Di peta, “kamu di sini” masuk akal. Di kertas yang tergeletak di meja dapur, tidak ada yang tahu “di sini” itu di mana.

Self bukan tipe tersendiri. Ia adalah placeholder (tempat kosong) yang diisi oleh setiap impl atau trait: di dalam impl Counter, Self berarti Counter; di dalam impl Timer, ia berarti Timer; di dalam trait, ia berarti “tipe mana pun yang mengimplementasikan trait ini”. Itulah yang membuatnya berguna: kamu bisa mengganti nama struct, atau menyalin method ke impl lain, dan Self ikut menyesuaikan.

Fungsi bebas (free function) tidak menjadi milik tipe mana pun, jadi tidak ada yang bisa mengisinya. Rust bisa saja mencoba menebak dari isi fungsinya, tapi kalau begitu sebuah signature akan bergantung pada kode di dalamnya, padahal Rust sengaja memeriksa signature secara terpisah. Lihat Struct untuk tempat yang biasa bagi fn new() -> Self.

Perbaikan 1: Pindahkan fungsinya ke blok impl

Section titled “Perbaikan 1: Pindahkan fungsinya ke blok impl”

Pilih ini hampir setiap saat. Fungsi yang membuat atau mengolah satu tipe tertentu tempatnya di blok impl tipe itu, dan di sana Self bekerja seperti yang kamu harapkan. Panggil dengan Counter::new():

struct Counter {
count: u32,
}
impl Counter {
fn new() -> Self {
Self { count: 0 }
}
fn increment(&mut self) {
self.count += 1;
}
}
fn main() {
let mut c = Counter::new();
c.increment();
c.increment();
println!("{}", c.count);
}

Output:

2
▶ Coba sendiri

Di dalam impl, kamu bisa memakai Self sebagai tipe (-> Self) sekaligus untuk membuat nilai (Self { count: 0 }). Lihat Struct.

Perbaikan 2: Tulis nama tipenya, bukan Self

Section titled “Perbaikan 2: Tulis nama tipenya, bukan Self”

Pilih ini kalau fungsinya memang harus tetap menjadi fungsi bebas, misalnya fungsi pembantu yang membuat beberapa tipe sekaligus, atau yang tinggal di modul lain. Tulis saja tipe sebenarnya, Counter, di tempat kamu menulis Self:

struct Counter {
count: u32,
}
fn new_counter(start: u32) -> Counter {
Counter { count: start }
}
fn reset(c: &mut Counter) {
c.count = 0;
}
fn main() {
let mut c = new_counter(10);
println!("{}", c.count);
reset(&mut c);
println!("{}", c.count);
}

Output:

10
0
▶ Coba sendiri

Ini juga perbaikan untuk fn reset(c: &mut Self) yang disalin keluar dari impl: setiap Self di signature dan di isi fungsinya diganti menjadi Counter.

Perbaikan 3: Pakai tipe generic kalau maksudmu “tipe apa saja”

Section titled “Perbaikan 3: Pakai tipe generic kalau maksudmu “tipe apa saja””

Pilih ini kalau kamu memakai Self dengan maksud “tipe apa pun yang diinginkan pemanggil”. Itu tugas untuk generic T, bukan Self. Deklarasikan <T> beserta trait yang dibutuhkan fungsinya. Di sini, T: Default membuat fungsinya bisa membuat nilai awal untuk tipe apa saja:

fn fresh_pair<T: Default>() -> (T, T) {
(T::default(), T::default())
}
fn main() {
let numbers: (u32, u32) = fresh_pair();
let words: (String, String) = fresh_pair();
println!("{:?}", numbers);
println!("{:?}", words);
}

Output:

(0, 0)
("", "")
▶ Coba sendiri

Kalau kamu ingin setiap tipe menentukan sendiri cara ia dibuat, taruh fungsinya di sebuah trait: trait Reset { fn fresh() -> Self; }. Di dalam trait, Self berarti “tipe yang mengimplementasikannya”. Lihat Generics dan Trait.

Self { ... } di main atau di fungsi bebas. let c = Self { count: 0 }; memberi E0411 dengan judul yang sedikit berbeda: cannot find struct, variant or union type `Self` in this scope. Perbaikannya: tulis Counter { count: 0 }, atau panggil Counter::new().

Fungsi pembantu yang bersarang di dalam method. Di dalam impl Counter, method yang berisi fn helper() -> Self miliknya sendiri mendapat kode lain, E0401: can't use `Self` from outer item (tidak bisa memakai Self dari item luar). Fungsi di dalam fungsi tidak mewarisi impl di luarnya. Perbaikannya: tulis Counter di fungsi dalamnya, atau pakai closure, atau pindahkan helper ke atas, ke dalam impl, sebagai method tersendiri.

Tertukar antara Self dan self. Self dengan huruf kapital adalah tipe; self dengan huruf kecil adalah nilai tempat sebuah method dipanggil. Memakai self di luar method adalah error yang berbeda, E0424. Perbaikan untuk keduanya: pastikan kodenya berada di dalam blok impl yang tepat.

  • E0424: self (huruf kecil, nilainya) dipakai di luar method.
  • E0425: tidak bisa menemukan nilai, fungsi, atau (sejak Rust 1.93) tipe dengan nama biasa.
  • E0412: kode lama untuk “cannot find type”, sekarang dilaporkan sebagai E0425.
  • E0405: tidak bisa menemukan sebuah trait, biasanya karena kurang baris use.
  • E0401: Self dari impl luar dipakai di dalam fungsi bersarang, ditunjukkan di atas.
  • Semua error compiler: daftar lengkap halaman error.

Kuis singkat

1. Di mana kamu bisa memakai Self sebagai tipe?

2. fn make_user() -> Self di level atas memberi E0411. Apa perbaikan yang biasa?

3. Di dalam impl Counter, apa yang dibuat oleh Self { count: 0 }?

Skor: 0 / 3