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のコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”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 here2 | 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 here2 | 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 は、見つからない変数や関数も扱うコードです。以下の内容は、どちらのコードでもまったく同じように当てはまります。
エラーの意味
Section titled “エラーの意味”^^^^^^ は、シグネチャの中の 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 がこうする理由
Section titled “Rust がこうする理由”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']));}実行結果:
100y構造体でも同じです。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::*; と書いて、親モジュールのものを全部インポートします。
よく出会う場面
Section titled “よく出会う場面”宣言していないファイルの型。 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 の行を追加します。詳しくはトレイトを見てください。
関連するエラー
Section titled “関連するエラー”- E0425:値や関数、そして Rust 1.93 からは型も見つからない。今のコンパイラで実際に目にするのは、このコードです。
- E0433:
HashMap::new()やmodels::Userのようなパスの、最初の部分が見つからない。 - E0432:インポートを解決できない。
useの行そのものが、何もないところを指しているときです。 - E0603:型は見つかったけれど、
pubではない。 - E0405(トレイトが見つからない)と E0411(impl の外の
Self):上で紹介した、よく似た親戚のエラーです。 - コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
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
さらに詳しく
Section titled “さらに詳しく”- E0412 — Rust error codes index(英語):公式のページです。このコードはもう出力されないという注記と、昔からの例が載っています。
- E0425 — Rust error codes index(英語):今のコンパイラがこのエラーに使っているコードです。
- ジェネリックなデータ型 — The Rust Programming Language 日本語版:
<T>の宣言のしかたを、直し方3と同じlargest関数で説明している章です。 - useキーワードでパスをスコープに持ち込む — The Rust Programming Language 日本語版:ほかのモジュールの型を使うための
use、crate::、super::を説明しています。 std::prelude— 標準ライブラリのドキュメント(英語):インポートせずに使える名前の一覧です。