Ошибка Rust E0412: cannot find type in this scope (тип не найден)
E0412 значит, что ты написал имя типа, которое Rust не видит из этого места, например в сигнатуре функции вроде fn print_invoice(inv: &Invoce). Ошибка очень частая и простая: опечатка, забытая строка use или обобщённый <T>, который ты забыл объявить. Сначала может сбить с толку одно: начиная с Rust 1.93 компилятор выводит эту ошибку как E0425, с тем же сообщением cannot find type. Эта страница описывает оба варианта и входит в справочник по ошибкам компилятора.
Сообщение об ошибке
Заголовок раздела «Сообщение об ошибке»Вот что выводят 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`Компилятор говорит: тип Invoce не найден в этой области видимости, но есть структура с похожим именем, Invoice. Вот программа, которая выдаёт обе ошибки (комментарий значит «опечатка: Invoce»):
struct Invoice { total: u32 }fn print_invoice(inv: &Invoce) { // ❌ typo: Invoce println!("{}", inv.total);}
fn main() { print_invoice(&Invoice { total: 120 });}Официальная страница E0412 (на английском) теперь начинается со слов «this error code is no longer emitted by the compiler» (компилятор больше не выдаёт этот код ошибки). Сама проблема никуда не делась, она просто переехала в 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 не знает.
Это как рецепт, где написано «добавь 200 г Invoce». Повар знает, что такое мука и сахар, но не «Invoce», поэтому останавливается, даже не начав.
Почему Rust так делает
Заголовок раздела «Почему Rust так делает»Rust проверяет сигнатуру каждой функции ещё до запуска программы. Каждый параметр и тип возвращаемого значения должны называть настоящий, известный тип, потому что по нему Rust решает, сколько памяти нужно значению и какие у него методы и поля. Гадать над именем, которое он не может найти, Rust не готов.
Без use видно везде лишь небольшое количество имён типов — это прелюдия (prelude): String, Vec, Option, Result, Box и ещё несколько. Для всего остального нужно либо твоё собственное определение, либо строка use, либо полный путь вроде std::num::ParseIntError. Как работают пути и use, смотри в уроке Модули.
Почему поменялся код? Начиная с Rust 1.93 rustc сообщает о пропавшем типе под кодом E0425 — тем же, что уже использовался для пропавшей переменной или функции. В сообщении по-прежнему написано type, так что всегда видно, какое имя потерялось.
Как исправить
Заголовок раздела «Как исправить»Исправление 1: исправь написание или объяви тип
Заголовок раздела «Исправление 1: исправь написание или объяви тип»Выбирай этот вариант, когда rustc говорит, что есть похожее имя, или не даёт подсказки вообще. Имена типов чувствительны к регистру: invoice, Invoce и Invoice — три разных имени. Если похожего имени нет, сначала напиши struct или enum:
struct Invoice { total: u32,}
fn print_invoice(inv: &Invoice) { println!("Сумма счёта: {} EUR", inv.total);}
fn main() { print_invoice(&Invoice { total: 120 });}Вывод:
Сумма счёта: 120 EURИсправление 2: добавь строку use, которую предлагает rustc
Заголовок раздела «Исправление 2: добавь строку use, которую предлагает rustc»Выбирай этот вариант, когда подсказка говорит consider importing this struct (или enum, или псевдоним типа). Типам стандартной библиотеки, которых нет в прелюдии, например 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; |Скопируй предложенную строку в начало файла:
use std::num::ParseIntError;
fn parse_age(text: &str) -> Result<u8, ParseIntError> { text.trim().parse()}
fn main() { println!("{:?}", parse_age(" 42 ")); println!("{:?}", parse_age("сорок").is_err());}Вывод:
Ok(42)trueЕсли ты написал HashMap::new() (путь с ::), а не тип в сигнатуре, ошибка будет E0433, и исправит её та же строка use. Если rustc предлагает несколько импортов, прочитай их, прежде чем выбрать: это разные типы с одинаковым именем.
Исправление 3: объяви параметр обобщённого типа
Заголовок раздела «Исправление 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. Добавь <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: импортируй тип из другого модуля
Заголовок раздела «Исправление 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!("Заказ №{}: {} EUR", order.id, order.total) }}
fn main() { let order = Order { id: 7, total: 42 }; println!("{}", receipts::print(&order));}Вывод:
Заказ №7: 42 EURВ обратную сторону всё так же: тип, объявленный в mod shop, должен быть pub struct Product, а main нужен use crate::shop::Product; (или полный путь shop::Product), чтобы его назвать. Чаще всего с этим сталкиваешься в mod tests, где use super::*; в начале импортирует всё из родительского модуля.
Где это обычно встречается
Заголовок раздела «Где это обычно встречается»Тип из файла, который ты не объявил. fn save(user: models::User) при наличии файла src/models.rs, но без строки mod models; — это не E0412 и не E0425, а E0433: cannot find module or crate `models` in this scope. Исправление: добавь mod models; в начало main.rs и сделай структуру pub.
Self вне impl. fn new_counter() -> Self на верхнем уровне даёт свой код, E0411: cannot find type `Self` in this scope, с пометкой `Self` is only available in impls, traits, and type definitions. Исправление: перенеси функцию в impl Counter { ... } или напиши Counter вместо Self.
Трейт вместо типа. impl Display for Point без импорта Display даёт E0405, cannot find trait `Display` in this scope, с 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 (
Selfвне impl): близкие родственники, показанные выше. - Все ошибки компилятора: полный список страниц об ошибках.
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. В уроке, по которому ты учишься, показано error[E0412]: cannot find type, а твой компилятор выводит error[E0425]: cannot find type. Почему?
2. fn first(items: &[T]) -> &T даёт cannot find type T. Как исправить?
3. Функция внутри mod billing использует Order — структуру, объявленную в начале main.rs. Какая строка внутри модуля это исправит?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- E0412 — Rust error codes index (на английском): официальная страница с пометкой, что этот код больше не выдаётся, и классическими примерами.
- E0425 — Rust error codes index (на английском): код, который сегодняшний компилятор использует для этой ошибки.
- Обобщённые типы данных — книга «Язык программирования Rust» (перевод на русский): как объявлять
<T>, с той же функциейlargest, что в исправлении 3. - Введение путей в область видимости с помощью ключевого слова use — книга «Язык программирования Rust» (перевод на русский):
use,crate::иsuper::для типов из других модулей. std::prelude— документация стандартной библиотеки (на английском): список имён, которыми можно пользоваться без импорта.