コンテンツにスキップ

Rustのエラー E0412: cannot find type in this scope(型が見つからない)

E0412 は、その場所からは Rust に見えない型の名前を書いた、という意味のエラーです。たとえば、fn print_invoice(inv: &Invoce) のような関数のシグネチャの中で起こります。とてもよく出会うエラーですが、直すのは簡単です。原因はタイプミスか、use の行の書き忘れか、ジェネリックな <T> の宣言忘れです。ただ、最初に戸惑うかもしれないことが1つあります。Rust 1.93 以降、コンパイラはこのエラーを E0425 として表示します。メッセージは同じ cannot find type です。このページでは両方を扱います。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。

Rust 1.93 以降では、次のように表示されます(現在のコンパイラは 1.97 です)。

error[E0425]: cannot find type `Invoce` in this scope
--> src/main.rs:2:24
|
1 | struct Invoice { total: u32 }
| -------------- similarly named struct `Invoice` defined here
2 | fn print_invoice(inv: &Invoce) { // ❌ typo: Invoce
| ^^^^^^
|
help: a struct with a similar name exists
|
2 | fn print_invoice(inv: &Invoice) { // ❌ typo: Invoce
| +

そして、同じプログラムを Rust 1.92 以前でコンパイルすると、次のようになります。ブログ記事や Stack Overflow の回答の多くは、このバージョンで書かれています。

error[E0412]: cannot find type `Invoce` in this scope
--> src/main.rs:2:24
|
1 | struct Invoice { total: u32 }
| -------------- similarly named struct `Invoice` defined here
2 | fn print_invoice(inv: &Invoce) {
| ^^^^^^ help: a struct with a similar name exists: `Invoice`

「cannot find type Invoce in this scope」は「このスコープに Invoce という型が見つからない」という意味です。similarly named struct `Invoice` defined here は「似た名前の構造体 Invoice がここで定義されている」、help は「似た名前の構造体がある」と教えてくれています。

両方のエラーが出るのは、次のプログラムです。

struct Invoice { total: u32 }
fn print_invoice(inv: &Invoce) { // ❌ typo: Invoce
println!("{}", inv.total);
}
fn main() {
print_invoice(&Invoice { total: 120 });
}

コメントは「タイプミス:Invoce」という意味です(エラーになる例なので、コードはそのままにしています)。

公式の E0412 のページ(英語)は、今では「this error code is no longer emitted by the compiler」(このエラーコードはもうコンパイラから出力されない)という一文で始まっています。問題がなくなったわけではなく、E0425 に移っただけです。E0425 は、見つからない変数や関数も扱うコードです。以下の内容は、どちらのコードでもまったく同じように当てはまります。

^^^^^^ は、シグネチャの中の Invoce を指しています。この関数をチェックするには、Rust は Invoce が何なのか(大きさはどれくらいか、どんなフィールドがあるか)を知らなければなりません。そこで、2行目から見えるすべての型(自分の構造体と列挙型、use の行、プレリュード)を調べましたが、その名前のものは見つかりませんでした。

help: の行を見れば、どの状況なのかがわかります。

  • 「a struct with a similar name exists」(似た名前の構造体がある):タイプミスです。+ が足りない文字を示しています。
  • 「consider importing this struct」(この構造体をインポートすることを検討してください):型はほかの場所にあるので、use の行が必要です。
  • 「you might be missing a type parameter」(型パラメータが足りないのかもしれません):ジェネリックな T を、<T> で宣言せずに使いました。
  • ヒントが何もない:その型はまだ存在しません。まだ書いていないか、Rust が知らないファイルにあります。

「Invoce を200グラム加える」と書かれたレシピのようなものです。料理人は小麦粉や砂糖なら知っていますが、「Invoce」は知らないので、作り始める前に手が止まってしまいます。

Rust は、プログラムを実行する前に、すべての関数のシグネチャをチェックします。引数と戻り値の型は、どれも実在する、知っている型の名前でなければなりません。Rust はその型を使って、値にどれだけのメモリが必要か、どんなメソッドやフィールドがあるかを決めるからです。見つからない名前を、推測で埋めることはしません。

use なしでどこからでも見える型の名前は、ほんの少ししかありません。プレリュード(prelude)にある String、Vec、Option、Result、Box などです。それ以外は、自分で定義するか、use の行を書くか、std::num::ParseIntError のようにフルパスで書く必要があります。パスと use のしくみは、モジュールを見てください。

なぜコードが変わったのでしょうか。Rust 1.93 から、rustc は見つからない型を E0425 として報告するようになりました。見つからない変数や関数に、もともと使っていたのと同じコードです。メッセージには今でも type と書かれているので、どの種類の名前が見つからなかったのかは、いつでも見分けられます。

直し方1:つづりを直す、または型を定義する

Section titled “直し方1:つづりを直す、または型を定義する”

rustc が「似た名前がある」と言っているとき、またはヒントが何もないときは、これを選びます。型の名前は大文字と小文字を区別します。invoice、Invoce、Invoice は3つの別々の名前です。似た名前がないなら、先に struct や enum を書きましょう。

struct Invoice {
total: u32,
}
fn print_invoice(inv: &Invoice) {
println!("請求書の合計: {} ユーロ", inv.total);
}
fn main() {
print_invoice(&Invoice { total: 120 });
}

実行結果:

請求書の合計: 120 ユーロ
▶ 実際に試してみよう

直し方2:rustc が提案する use の行を追加する

Section titled “直し方2:rustc が提案する use の行を追加する”

ヒントが consider importing this struct(または enum や type alias)と言っているときは、これを選びます。HashMap、ParseIntError、Ordering のような、プレリュードに含まれない標準ライブラリの型には、use の行が必要です。次の例では、関数がパースのエラーを返しています。

error[E0425]: cannot find type `ParseIntError` in this scope
--> src/main.rs:1:40
|
1 | fn parse_age(text: &str) -> Result<u8, ParseIntError> {
| ^^^^^^^^^^^^^ not found in this scope
|
help: consider importing this struct
|
1 + use std::num::ParseIntError;
|

not found in this scope は「このスコープには見つからない」という意味です。

提案された行を、ファイルの先頭にコピーしましょう。

use std::num::ParseIntError;
fn parse_age(text: &str) -> Result<u8, ParseIntError> {
text.trim().parse()
}
fn main() {
println!("{:?}", parse_age(" 42 "));
println!("{:?}", parse_age("forty").is_err());
}

実行結果:

Ok(42)
true
▶ 実際に試してみよう

シグネチャの中の型ではなく、HashMap::new()(:: を含むパス)と書いた場合は、エラーは E0433 になりますが、同じ use の行で直ります。rustc がいくつもインポートを提案してきたら、選ぶ前によく読みましょう。名前が同じだけの、別々の型です。

直し方3:ジェネリックな型パラメータを宣言する

Section titled “直し方3:ジェネリックな型パラメータを宣言する”

ヒントが you might be missing a type parameter と言っているときは、これを選びます。Rust では、T は特別な単語ではありません。自分で考えた名前なので、関数名のあとの山かっこ < > の中で宣言しなければなりません。<T> がないと、Rust は T という名前の本物の型を探してしまいます。

error[E0425]: cannot find type `T` in this scope
--> src/main.rs:1:21
|
1 | fn largest(items: &[T]) -> &T {
| ^ not found in this scope
|
help: you might be missing a type parameter
|
1 | fn largest<T>(items: &[T]) -> &T {
| +++

このエラーは、T が出てくる場所ごとに1回ずつ表示されます。<T> を追加し、さらに関数に必要なトレイトも書きましょう。要素を > で比べるには、T が PartialOrd を実装している必要があります。

fn largest<T: PartialOrd>(items: &[T]) -> &T {
let mut best = &items[0];
for item in items {
if item > best {
best = item;
}
}
best
}
fn main() {
println!("{}", largest(&[34, 50, 25, 100, 65]));
println!("{}", largest(&['y', 'm', 'a', 'q']));
}

実行結果:

100
y
▶ 実際に試してみよう

構造体でも同じです。struct Wrapper { items: Vec<Item> } は、struct Wrapper<Item> と書くか、本物の Item 型を定義しない限りエラーになります。: PartialOrd を省くと、代わりに > のところで E0369 になります。詳しくはジェネリックな関数を見てください。

直し方4:別のモジュールから型をインポートする

Section titled “直し方4:別のモジュールから型をインポートする”

型は自分のものだけれど、別のモジュールにあるときは、これを選びます。よくある驚きは、ファイルの中にあるモジュールからも、ファイルの先頭にある型が見えない、ということです。モジュールはそれぞれ自分のスコープを持っているのです。

error[E0425]: cannot find type `Order` in this scope
--> src/main.rs:7:26
|
7 | pub fn print(order: &Order) -> String {
| ^^^^^ not found in this scope
|
help: consider importing this struct
|
7 + use crate::Order;
|

7 + は「モジュールの中の7行目に、この行を追加して」という意味です。crate::Order はクレートの一番上からのパスです。super::Order(「親モジュールから」)でも動きます。

struct Order {
id: u32,
total: u32,
}
mod receipts {
use crate::Order;
pub fn print(order: &Order) -> String {
format!("注文番号{}:{} ユーロ", order.id, order.total)
}
}
fn main() {
let order = Order { id: 7, total: 42 };
println!("{}", receipts::print(&order));
}

実行結果:

注文番号7:42 ユーロ
▶ 実際に試してみよう

逆向きも同じです。mod shop の中で定義した型を main で使うには、pub struct Product にして、use crate::shop::Product; と書く(またはフルパスで shop::Product と書く)必要があります。これにいちばんよく出会うのは mod tests の中です。そこでは、先頭に use super::*; と書いて、親モジュールのものを全部インポートします。

宣言していないファイルの型。 src/models.rs というファイルがあるのに mod models; の行がない状態で fn save(user: models::User) と書くと、E0412 でも E0425 でもなく E0433 になります。cannot find module or crate `models` in this scope(このスコープにモジュールまたはクレート models が見つからない)と表示されます。直し方:main.rs の先頭に mod models; を追加し、構造体を pub にします。

impl の外の Self。 トップレベルで fn new_counter() -> Self と書くと、専用のコード E0411 になります。cannot find type `Self` in this scope(このスコープに型 Self が見つからない)と表示され、`Self` is only available in impls, traits, and type definitions(Self が使えるのは impl、トレイト、型定義の中だけ)というラベルが付きます。直し方:関数を impl Counter { ... } の中に移すか、Self の代わりに Counter と書きます。

型ではなくトレイト。 Display をインポートせずに impl Display for Point と書くと、E0405 になります。cannot find trait `Display` in this scope(このスコープにトレイト Display が見つからない)と表示され、help: consider importing this trait(このトレイトをインポートすることを検討してください)と use std::fmt::Display; が提案されます。考え方も直し方も同じで、use の行を追加します。詳しくはトレイトを見てください。

  • E0425:値や関数、そして Rust 1.93 からは型も見つからない。今のコンパイラで実際に目にするのは、このコードです。
  • E0433:HashMap::new() や models::User のようなパスの、最初の部分が見つからない。
  • E0432:インポートを解決できない。use の行そのものが、何もないところを指しているときです。
  • E0603:型は見つかったけれど、pub ではない。
  • E0405(トレイトが見つからない)と E0411(impl の外の Self):上で紹介した、よく似た親戚のエラーです。
  • コンパイルエラーの一覧:エラー解説ページの全リストです。

理解度チェック

1. チュートリアルには error[E0412]: cannot find type と書いてあるのに、自分のコンパイラでは error[E0425]: cannot find type と表示されます。なぜですか?

2. fn first(items: &[T]) -> &T で cannot find type T になります。どう直しますか?

3. mod billing の中の関数が、main.rs の先頭で定義した構造体 Order を使っています。モジュールの中にどの行を書けば直りますか?

スコア: 0 / 3