Rustのエラー E0411: cannot find type Self in this scope(implの外でのSelf)
E0411 は、Rust が何を指しているのかわからない場所で Self を書いた、という意味のエラーです。Self は「この impl ブロック(またはトレイト)が扱っている型」の省略形なので、impl、トレイト、型の定義の中でしか使えません。よくある原因は、ファイルのトップレベルに書いた fn new() -> Self のようなコンストラクタや、impl ブロックからコピーして外に出したメソッドです。よく出会うエラーですが、すぐに直せます。Rust 1.93 で E0425 に変わった E0412 と違って、このコードは変わっていません。rustc 1.97 でも E0411 と表示されます。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”error[E0411]: cannot find type `Self` in this scope --> src/main.rs:5:21 |5 | fn new_counter() -> Self { // ❌ `Self` outside an `impl` | ----------- ^^^^ `Self` is only available in impls, traits, and type definitions | | | `Self` not allowed in a function「cannot find type Self in this scope」は「このスコープに型 Self が見つからない」という意味です。
このエラーが出るのは、次のプログラムです。
struct Counter { count: u32,}
fn new_counter() -> Self { // ❌ `Self` outside an `impl` Counter { count: 0 }}
fn main() { let c = new_counter(); println!("{}", c.count);}コメントは「impl の外の Self」という意味です(エラーになる例なので、コードはそのままにしています)。
エラーの意味
Section titled “エラーの意味”rustc は5行目の2か所を指しています。
Selfの下の^^^^:「Selfis only available in impls, traits, and type definitions」(Selfは impl、トレイト、型の定義の中でしか使えない)。これがルールそのものです。new_counterの下の-----:「Selfnot allowed in a function」(関数の中ではSelfは使えない)。今回の理由はこれです。new_counterはただの関数で、どのimplにも属していません。
Counter { count: 0 } と書いたばかりなので、new_counter が Counter を返すことは、あなたにはわかっています。でも Rust は、Self の意味を推測するために関数の中身を読んだりはしません。Self が意味を持つのは、外側に impl Counter { ... } や trait ... { ... } があるときだけで、ここにはそれがありません。
付せんに書かれた「ここ」という言葉のようなものです。地図の上なら「現在地はここ」で意味が通じます。でも、台所のテーブルに置かれた付せんでは、「ここ」がどこなのか誰にもわかりません。
Rust がこうする理由
Section titled “Rust がこうする理由”Self は、それ自体が1つの型なのではありません。それぞれの impl やトレイトが中身を埋めるプレースホルダー(仮の名前)です。impl Counter の中では Self は Counter を、impl Timer の中では Timer を意味します。トレイトの中では「このトレイトを実装する型、どれでも」という意味です。だからこそ便利なのです。構造体の名前を変えても、メソッドを別の impl にコピーしても、Self は自動でついてきます。
自由関数(どの型にも属さない関数)は、どの型にも属していないので、埋めるものがありません。Rust が中身から推測することもできたかもしれませんが、そうするとシグネチャが中のコードに左右されてしまいます。Rust はあえて、シグネチャをそれだけで検査するようにしています。fn new() -> Self がふつうどこに置かれるかは、構造体を見てください。
直し方1:関数を impl ブロックに移す
Section titled “直し方1:関数を impl ブロックに移す”たいていはこれを選びます。1つの型を作ったり扱ったりする関数は、その型の impl ブロックに入れるのが自然です。そこなら、Self は期待どおりに使えます。呼び出すときは 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);}実行結果:
2impl の中では、Self を型として(-> Self)も、値を作るため(Self { count: 0 })にも使えます。メソッドで振る舞いを追加するを見てください。
直し方2:Self の代わりに型の名前を書く
Section titled “直し方2:Self の代わりに型の名前を書く”関数を自由関数のままにしておきたいときは、これを選びます。たとえば、いくつかの型を作るヘルパーや、別のモジュールにある関数です。Self と書いたところに、本当の型 Counter を書くだけです。
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);}実行結果:
100impl からコピーして外に出した fn reset(c: &mut Self) も、これで直せます。シグネチャと中身にある Self を、すべて Counter にします。
直し方3:「どんな型でも」のつもりならジェネリックな型を使う
Section titled “直し方3:「どんな型でも」のつもりならジェネリックな型を使う”「呼び出す側が望む型なら何でも」という意味で Self を使ったなら、これを選びます。それは Self ではなく、ジェネリックな T の仕事です。関数が必要とするトレイトを付けて <T> を宣言します。ここでは T: Default のおかげで、関数がどんな型でも初期値を作れます。
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);}実行結果:
(0, 0)("", "")作り方をそれぞれの型に決めさせたいなら、関数をトレイトに入れます。trait Reset { fn fresh() -> Self; } のように書きます。トレイトの中では、Self は「それを実装する型」という意味になります。ジェネリクスとトレイトを定義するを見てください。
よく出会う場面
Section titled “よく出会う場面”main や自由関数の中の Self { ... }。 let c = Self { count: 0 }; と書くと、少し違う見出しで E0411 になります。cannot find struct, variant or union type `Self` in this scope(このスコープに構造体、バリアント、共用体の型 Self が見つからない)です。直し方:Counter { count: 0 } と書くか、Counter::new() を呼びます。
メソッドの中に入れ子にしたヘルパー関数。 impl Counter の中のメソッドが、自分の中に fn helper() -> Self を持っていると、別のコード E0401 になります。can't use `Self` from outer item(外側のアイテムの Self は使えない)です。関数の中の関数は、外側の impl を引き継ぎません。直し方:内側の関数には Counter と書くか、クロージャを使うか、helper を impl の中の独立したメソッドに移します。
Self と self の取り違え。 大文字の Self は型で、小文字の self はメソッドを呼び出した値です。メソッドの外で self を使うと、別のエラー E0424 になります。どちらの直し方も同じで、コードが正しい impl ブロックの中にあるか確かめます。
関連するエラー
Section titled “関連するエラー”- E0424:
self(小文字、値のほう)をメソッドの外で使った。 - E0425:ふつうの名前の値、関数、(Rust 1.93 以降は)型が見つからない。
- E0412:「cannot find type」(型が見つからない)の古いコードで、今は E0425 として表示されます。
- E0405:トレイトが見つからない。たいていは
useの行の書き忘れです。 - E0401:外側の
implのSelfを、入れ子の関数の中で使った。上で紹介しました。 - コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. Self を型として使えるのはどこですか?
2. トップレベルの fn make_user() -> Self で E0411 が出ました。ふつうの直し方はどれですか?
3. impl Counter の中で、Self { count: 0 } は何を作りますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0411 — Rust error codes index(英語):このエラーの公式の説明です。
Selfが何を表すのか、なぜ impl、トレイト、型の定義の中でしか使えないのかを説明しています。 - 関連関数 — The Rust Programming Language 日本語版:
fn square(size: u32) -> Selfのような関連関数と、implの中でのSelfの使い方です。 - The
Selfkeyword — standard library docs(英語):impl、トレイト、型の定義の中でSelfが何を意味するかです。 Selfin paths — The Rust Reference(英語):入れ子のアイテムが外側のSelfを使えない理由も含めた、正確なルールです。