コンテンツにスキップ

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のコンパイルエラー解説を見てください。

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」という意味です(エラーになる例なので、コードはそのままにしています)。

rustc は5行目の2か所を指しています。

  1. Self の下の ^^^^:「Self is only available in impls, traits, and type definitions」(Self は impl、トレイト、型の定義の中でしか使えない)。これがルールそのものです。
  2. new_counter の下の -----:「Self not allowed in a function」(関数の中では Self は使えない)。今回の理由はこれです。new_counter はただの関数で、どの impl にも属していません。

Counter { count: 0 } と書いたばかりなので、new_counter が Counter を返すことは、あなたにはわかっています。でも Rust は、Self の意味を推測するために関数の中身を読んだりはしません。Self が意味を持つのは、外側に impl Counter { ... } や trait ... { ... } があるときだけで、ここにはそれがありません。

付せんに書かれた「ここ」という言葉のようなものです。地図の上なら「現在地はここ」で意味が通じます。でも、台所のテーブルに置かれた付せんでは、「ここ」がどこなのか誰にもわかりません。

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);
}

実行結果:

2
▶ 実際に試してみよう

impl の中では、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);
}

実行結果:

10
0
▶ 実際に試してみよう

impl からコピーして外に出した 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 は「それを実装する型」という意味になります。ジェネリクスとトレイトを定義するを見てください。

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 ブロックの中にあるか確かめます。

  • E0424:self(小文字、値のほう)をメソッドの外で使った。
  • E0425:ふつうの名前の値、関数、(Rust 1.93 以降は)型が見つからない。
  • E0412:「cannot find type」(型が見つからない)の古いコードで、今は E0425 として表示されます。
  • E0405:トレイトが見つからない。たいていは use の行の書き忘れです。
  • E0401:外側の impl の Self を、入れ子の関数の中で使った。上で紹介しました。
  • コンパイルエラーの一覧:エラー解説ページの全リストです。

理解度チェック

1. Self を型として使えるのはどこですか?

2. トップレベルの fn make_user() -> Self で E0411 が出ました。ふつうの直し方はどれですか?

3. impl Counter の中で、Self { count: 0 } は何を作りますか?

スコア: 0 / 3