콘텐츠로 이동

Rust 에러 E0433: failed to resolve, use of undeclared type (선언되지 않은 타입)

E0433은 HashMap::new()나 rand::rng() 같은 경로를 썼는데, Rust가 그 첫 부분이 무엇인지 모른다는 뜻이에요. 거의 항상 한 줄이 빠져 있어요. use 줄, Cargo.toml의 의존성, 또는 mod 선언이에요. 다행히 rustc가 보통 그 줄을 그대로 출력해 주니까 복사해서 붙이면 돼요. 이 페이지는 Rust 컴파일러 에러 해설의 일부예요.

error[E0433]: cannot find type `HashMap` in this scope
--> src/main.rs:2:21
|
2 | let mut stock = HashMap::new();
| ^^^^^^^ use of undeclared type `HashMap`
|
help: consider importing this struct
|
1 + use std::collections::HashMap;
|

“이 스코프에서 HashMap 타입을 찾을 수 없고, 선언되지 않은 타입 HashMap을 썼다”는 뜻이에요. help는 “이 구조체를 가져와 보라”며 넣을 줄을 보여 줘요.

이 에러를 내는 프로그램은 다음과 같아요.

fn main() {
let mut stock = HashMap::new();
stock.insert("apples", 12);
println!("{:?}", stock.get("apples"));
}

예전 Rust 버전은 같은 에러를 “failed to resolve: use of undeclared type HashMap”(해석 실패: 선언되지 않은 타입 사용)이라고 출력해요. 무엇이 빠졌느냐에 따라 라벨이 use of undeclared type 대신 use of unresolved module or unlinked crate(찾을 수 없는 모듈이나 연결되지 않은 크레이트 사용, 크레이트나 모듈일 때)라고 나오기도 해요. 모두 E0433이고, 고치는 방법도 같아요.

^^^^^^^는 HashMap, 즉 ::의 앞부분을 가리켜요. HashMap::new()를 호출하려면 Rust는 먼저 HashMap이라는 것을 찾아야 해요. 2번째 줄에서 보이는 모든 것을 살펴봤지만 그런 이름이 없었고, 그래서 new는 찾기 시작할 수조차 없었어요.

중요한 건 help: 줄이에요. rustc가 표준 라이브러리를 뒤져서 std::collections에 있는 HashMap이라는 구조체를 찾았고, 그걸 보이게 해 줄 use 줄을 보여 줘요. 1 +는 “이걸 1번째 줄로 추가하라”는 뜻이에요.

도서관 사서에게 책 제목은 말하지 않고 “그 책의 3장 주세요”라고 하는 것과 비슷해요. 3장이 있는 책은 많지만, 사서는 먼저 제목을 알아야 해요.

모든 Rust 파일에서 자동으로 보이는 이름은 몇 개 안 돼요. 이걸 프렐루드(prelude)라고 해요. Vec, String, Option, Some, None, Result, Ok, Err, Box, 그리고 몇 가지 트레이트예요. HashMap, HashSet, fs, Ordering을 포함한 나머지는 모두 use로 가져오거나 전체 경로로 써야 해요.

이렇게 하면 프렐루드가 작게 유지되고 이름 충돌도 피할 수 있어요. 예를 들어 표준 라이브러리에는 서로 다른 Ordering 타입이 두 개 있고, 내 코드에도 Duration이나 Result가 있을 수 있어요. Rust는 내가 어느 쪽을 뜻했는지 짐작하지 않아요. 파일 맨 위에 한 번 적어 두면, 코드를 읽는 누구나 각 이름이 어디서 왔는지 알 수 있어요.

크레이트와 모듈도 마찬가지예요. 크레이트는 Cargo.toml에 적힌 뒤에야, 모듈은 mod 줄이 있어야 내 코드에 존재해요. 모듈과 Cargo와 크레이트를 참고하세요.

방법 1: rustc가 제안하는 use 줄 추가하기

섹션 제목: “방법 1: rustc가 제안하는 use 줄 추가하기”

help:가 consider importing(가져와 보라)이라고 말할 때 이 방법을 고르세요. 단연 가장 흔한 해결책이에요. 제안된 줄을 파일 맨 위에 복사하세요.

use std::collections::HashMap;
fn main() {
let mut stock = HashMap::new();
stock.insert("apples", 12);
println!("{:?}", stock.get("apples"));
}

실행 결과:

Some(12)
▶ 직접 실행해 보기

다른 방법은 호출하는 곳에서 std::collections::HashMap::new()처럼 전체 경로를 쓰는 거예요. 이것도 동작하지만 쓸 때마다 반복해야 하니, 보통은 use 줄을 써요. 이 타입에 대해서는 HashMap에서 더 볼 수 있어요.

rustc가 가져올 후보를 여러 개 보여 주면(consider importing one of these), 하나를 고르기 전에 꼭 읽어 보세요. 이름만 같은 서로 다른 타입이고, 그중 하나만 내가 원한 거예요.

방법 2: 타입 이름을 고치거나 타입 선언하기

섹션 제목: “방법 2: 타입 이름을 고치거나 타입 선언하기”

그 이름이 내가 만든 타입일 때 이 방법을 고르세요. help:가 아예 없다면 그 타입은 아직 없는 거예요. 오타라면 rustc가 비슷한 이름을 가리켜 줘요.

error[E0433]: cannot find type `Invetory` in this scope
--> src/main.rs:12:17
|
12 | let stock = Invetory::new();
| ^^^^^^^^ use of undeclared type `Invetory`
|
help: a struct with a similar name exists
|
12 | let stock = Inventory::new();
| +

help는 “비슷한 이름의 구조체가 있다”는 뜻이고, 줄 아래의 +가 빠진 글자를 보여 줘요. 철자를 고치세요.

struct Inventory {
items: Vec<String>,
}
impl Inventory {
fn new() -> Self {
Inventory { items: Vec::new() }
}
}
fn main() {
let stock = Inventory::new();
println!("물건 {}개", stock.items.len());
}

실행 결과:

물건 0개
▶ 직접 실행해 보기

Order::new()가 아무 제안 없이 E0433을 낸다면, 아직 struct Order를 쓰지 않은 거예요(또는 mod로 선언하지 않은 파일에 있거나요). 대문자도 확인하세요. inventory::new()와 Inventory::new()는 서로 다른 이름이에요.

방법 3: 타입이 들어 있는 모듈 이름 쓰기

섹션 제목: “방법 3: 타입이 들어 있는 모듈 이름 쓰기”

타입이나 열거형이 어떤 모듈 안에 정의되어 있는데 그 밖에서 쓸 때 이 방법을 고르세요. 여기서는 열거형이 mod traffic 안에 있는데, main이 Light::Green이라고 썼어요.

error[E0433]: cannot find type `Light` in this scope
--> src/main.rs:11:15
|
11 | let now = Light::Green;
| ^^^^^ use of undeclared type `Light`
|
help: consider importing this enum
|
1 + use crate::traffic::Light;
|

열거형을 가져오세요(또는 traffic::Light::Green이라고 쓰세요). 가져오는 건 열거형이고, 각 배리언트(variant)는 여전히 Light::Green처럼 써야 한다는 점을 기억하세요.

mod traffic {
#[derive(Debug)]
pub enum Light {
Red,
Yellow,
Green,
}
}
use crate::traffic::Light;
fn can_go(light: &Light) -> bool {
match light {
Light::Green => true,
Light::Yellow | Light::Red => false,
}
}
fn main() {
let now = Light::Green;
println!("{now:?}: 출발 가능 = {}", can_go(&now));
}

실행 결과:

Green: 출발 가능 = true
▶ 직접 실행해 보기

배리언트 경로는 정확히 두 부분, Enum::Variant로 이루어져요. Light::Red::Green처럼 한 부분을 더 쓰면 cannot find module `Red` in `Light` (Light에서 모듈 Red를 찾을 수 없음)와 `Red` is a variant, not a module(Red는 모듈이 아니라 배리언트) 라벨이 붙은 E0433이 나요. 열거형을 참고하세요.

방법 4: 크레이트를 추가하거나 모듈 선언하기

섹션 제목: “방법 4: 크레이트를 추가하거나 모듈 선언하기”

라벨이 use of unresolved module or unlinked crate라고 말할 때 이 방법을 고르세요. 경로의 첫 부분이 Rust가 모르는 크레이트나 모듈이에요.

error[E0433]: cannot find module or crate `rand` in this scope
--> src/main.rs:4:19
|
4 | let mut rng = rand::rng();
| ^^^^ use of unresolved module or unlinked crate `rand`
|
= help: if you wanted to use a crate named `rand`, use `cargo add rand` to add it to your `Cargo.toml`

help는 “rand라는 크레이트를 쓰려던 거라면 cargo add rand로 Cargo.toml에 추가하라”는 뜻이에요. crates.io의 크레이트라면 프로젝트 폴더에서 cargo add rand를 실행하세요. fs 같은 표준 라이브러리 모듈이라면 rustc가 대신 use std::fs;를 제안해요. 그리고 src/inventory.rs 같은 내 파일이라면 help가 to make use of source file src/inventory.rs, use `mod inventory` in this file to declare the module(src/inventory.rs를 쓰려면 이 파일에서 mod inventory로 모듈을 선언하라)이라고 말해요.

src/
├── main.rs inventory::count_items() ← 맨 위에 `mod inventory;` 필요
└── inventory.rs pub fn count_items() -> u32 { 42 }

아래는 같은 프로그램을 한 파일에 담은 거예요. Playground에서 실행되도록 모듈을 안에 바로 적었어요.

mod inventory {
pub fn count_items() -> u32 {
42
}
}
fn main() {
println!("재고 수량: {}", inventory::count_items());
}

실행 결과:

재고 수량: 42
▶ 직접 실행해 보기

파일을 따로 나눈다면, 달라지는 건 mod inventory { ... }가 mod inventory;가 되고 본문이 src/inventory.rs로 옮겨 간다는 것뿐이에요.

오래된 코드에서 extern crate rand;를 볼 수도 있어요. 2018 에디션부터는 필요 없어요. 크레이트가 Cargo.toml에 있으면 바로 쓸 수 있어요. extern crate를 추가해도 E0433은 고쳐지지 않아요. 의존성이 없으면 에러가 E0463, can't find crate for rand(rand 크레이트를 찾을 수 없음)로 바뀔 뿐이에요. 진짜 해결책은 cargo add예요.

cmp로 비교할 때. match a.cmp(&b)에 Ordering::Less 갈래를 쓰면 E0433이 나고, rustc가 use std::cmp::Ordering;과 use std::sync::atomic::Ordering; 두 가지를 제안해요. 원하는 건 std::cmp::Ordering이에요. atomic 쪽은 스레드용이에요. match를 참고하세요.

mod tests 블록 안의 테스트. 테스트 모듈은 자식 모듈이라서, 가져오지 않으면 내 타입을 볼 수 없어요. mod tests 안에서 Inventory::new()를 쓰면 help: consider importing this struct와 use crate::Inventory;가 붙은 E0433이 나요. 해결: 테스트 모듈 맨 위에 use super::*;를 넣으세요. 테스트를 참고하세요.

문서나 블로그 글에서 붙여 넣은 코드. 예제는 use 줄을 생략할 때가 많아요. fs::read_to_string(...)은 cannot find module or crate `fs` in this scope와 use std::fs;라는 help를 내며 실패해요. 해결: rustc가 보여 주는 줄을 추가하거나, 그 항목의 문서 페이지에서 경로를 확인하세요.

  • E0432: use 줄에서 생기는 같은 종류의 문제, unresolved import예요.
  • E0425: 오타 난 변수처럼 값이나 함수를 찾을 수 없어요(::는 없어요). 최신 rustc는 let m: HashMap<&str, u32>처럼 타입 자리에 빠진 타입에도 E0425를 쓰고, 예전 버전은 그걸 E0412라고 불러요. 같은 use 줄로 고쳐져요.
  • E0599: 타입은 찾았지만 :: 뒤의 메서드나 배리언트가 없어요. Light::Blue처럼요.
  • E0463: can't find crate. 의존성 없이 extern crate를 쓰면 나요.
  • 전체 컴파일러 에러: 에러 페이지 전체 목록이에요.

이해도 점검

1. Vec::new()는 아무것도 가져오지 않아도 되는데, HashSet::new()는 왜 E0433을 낼까요?

2. match a.cmp(&b)에 대해 rustc가 use std::cmp::Ordering;과 use std::sync::atomic::Ordering;을 둘 다 제안해요. 어느 쪽을 고를까요?

3. rand::rng()가 'use of unresolved module or unlinked crate' 라벨이 붙은 E0433을 내요. 무엇으로 고칠까요?

점수: 0 / 3