콘텐츠로 이동

Rust 에러 E0432: unresolved import (use 경로를 찾을 수 없음)

E0432는 use 줄 하나가 Rust가 찾을 수 없는 무언가를 가리킨다는 뜻이에요. 크레이트가 아직 Cargo.toml에 없을 수도 있고, 경로에 작은 오타가 있을 수도 있고, 파일은 있는데 Rust가 그게 모듈이라는 걸 모를 수도 있어요. 무서워 보이지만 거의 항상 한 줄만 고치면 되고, 어느 줄인지도 컴파일러가 대개 알려 줘요. 이 페이지는 Rust 컴파일러 에러 해설의 일부예요.

error[E0432]: unresolved import `rand`
--> src/main.rs:1:5
|
1 | use rand::random_range;
| ^^^^ 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`

“unresolved import rand“는 “rand를 가져올 수 없다”는 뜻이고, 라벨은 “rand라는 모듈을 찾을 수 없거나 연결되지 않은 크레이트”라고 말해요. help는 “rand라는 크레이트를 쓰려던 거라면 cargo add rand로 Cargo.toml에 추가하라”고 알려 줘요.

이 에러를 내는 프로그램은 다음과 같아요. [dependencies] 아래에 아무것도 없는, 막 cargo new로 만든 프로젝트예요.

use rand::random_range;
fn main() {
let roll = random_range(1..=6);
println!("You rolled {roll}");
}

^^^^ 아래의 문구는 원인에 따라 달라져요. 아래는 모두 E0432이고, 각각 아래의 다른 방법으로 이어져요.

라벨에 나오는 문구 보통 무엇이 잘못됐나요 해결
use of unresolved module or unlinked crate Cargo.toml에 크레이트가 없거나, mod 줄이 없는 파일 방법 1 또는 방법 3
could not find `collection` in `std` 경로 중간에 오타 방법 2
no `Hashmap` in `collections` 마지막 이름에 오타(또는 대소문자 틀림) 방법 2
could not find `inventory` in the crate root 선언하지 않은 모듈을 crate:: 경로로 가리킴 방법 3
no external crate 경로가 엉뚱한 모듈에서 시작함 방법 4

use 줄은 지름길이에요. use rand::random_range;는 “지금부터 random_range는 rand::random_range에 있는 것을 뜻한다”는 말이에요. Rust가 이 지름길을 만들려면, 경로를 한 조각씩 따라가야 해요. 먼저 rand를 찾고, 그다음 그 안에서 random_range를 찾아요.

^^^^는 실패한 첫 번째 조각을 가리켜요. 여기서는 맨 첫 조각인 rand라서, Rust는 random_range를 찾아보지도 못했어요. help: 줄은 그 이유를 짐작해 줘요. rand는 crates.io의 크레이트인데, 이 프로젝트에 아직 추가하지 않았다는 거죠.

택시 기사님께 “부산시 해운대구 바다로 12”라고 말해야 하는데 “부삼시”라고 말한 것과 비슷해요. 도시 이름이 틀리면 기사님은 길을 찾기 시작할 수조차 없어요.

Rust는 모든 경로를 프로그램이 실행될 때가 아니라 컴파일할 때 해석해요. “혹시 몰라서” 미리 불러오는 건 하나도 없어요. 코드가 볼 수 있는 건 세 가지뿐이에요. Cargo.toml에 적힌 크레이트(그리고 std), mod로 선언한 모듈, 그 안에 있는 항목들이에요. use 줄이 그 밖의 이름을 가리키면, Rust는 짐작하지 않고 바로 멈춰요.

이건 좋은 일이에요. Python이나 JavaScript에서는 가져오는 이름에 오타가 있어도 그 줄이 실제로 실행될 때에야, 어쩌면 운영 환경에서야 실패할 때가 많아요. Rust에서는 아예 빌드가 안 돼요. 또, 추가한 적 없는 크레이트가 몰래 프로그램에 끼어들 수도 없다는 뜻이에요.

2018 에디션부터 use 경로는 다음 중 한 곳에서 시작해요. 크레이트 이름(std, rand), crate(내 크레이트의 루트), self(현재 모듈), super(부모 모듈), 또는 현재 모듈 안에서 선언한 모듈이에요. 자세한 내용은 모듈 강좌에서, 의존성은 Cargo와 크레이트에서 설명해요.

방법 1: cargo add로 크레이트 추가하기

섹션 제목: “방법 1: cargo add로 크레이트 추가하기”

첫 조각이 rand, serde, regex처럼 crates.io의 크레이트이고, help: 줄에 cargo add가 나올 때 이 방법을 고르세요. 가장 흔한 원인이에요. 특히 블로그 글에서 코드를 복사했을 때 자주 나요. Cargo.toml이 있는 폴더에서 이렇게 실행하세요.

Terminal window
cargo add rand

Cargo가 최신 버전을 찾아서 Cargo.toml에 한 줄을 추가해 줘요.

[dependencies]
rand = "0.10.3"

이제 같은 코드가 빌드돼요. 이 버전은 주사위 값 대신 확인 결과를 출력해서, 출력이 항상 같아요.

use rand::random_range;
fn main() {
let roll = random_range(1..=6);
println!("주사위 값이 1~6 사이인가요? {}", (1..=6).contains(&roll));
}

실행 결과:

주사위 값이 1~6 사이인가요? true
▶ 직접 실행해 보기

여기서 자주 헷갈리는 게 두 가지 있어요. 첫째, 이름에 대시(-)가 있는 크레이트는 코드에서 밑줄(_)을 써요. cargo add tracing-subscriber로 추가하고, 코드에는 use tracing_subscriber::...라고 써요. 둘째, 크레이트가 워크스페이스의 의존성이라도, 그 크레이트를 쓰는 패키지의 Cargo.toml에도 적혀 있어야 해요.

라벨이 could not find `X` in `Y`(Y에서 X를 찾을 수 없음)나 no `X` in `Y`(Y에 X가 없음)라고 말할 때 이 방법을 고르세요. 경로 중간이나 끝의 무언가에 오타가 있어요. 대표적인 예를 볼게요.

error[E0432]: unresolved import `std::collection`
--> src/main.rs:1:10
|
1 | use std::collection::HashMap;
| ^^^^^^^^^^ could not find `collection` in `std`

모듈 이름은 s가 붙은 collections예요. 이름은 대소문자도 구분해요. use std::collections::Hashmap;은 no `Hashmap` in `collections`로 실패하고, rustc가 help: a similar name exists in the module(모듈에 비슷한 이름이 있음)과 함께 올바른 철자를 알려 줘요. 고친 코드는 이래요.

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

실행 결과:

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

정확한 경로가 기억나지 않으면 표준 라이브러리 문서(영어)에서 검색해 보세요. 각 항목의 페이지 맨 위에 전체 경로가 나와 있어요. 이 타입에 대해서는 HashMap을 참고하세요.

src/inventory.rs 같은 새 파일을 만들었는데 use inventory::...가 그 파일을 찾지 못할 때 이 방법을 고르세요. Rust에서 파일은 부모 파일이 선언하기 전까지 모듈이 아니에요. 프로젝트가 이렇게 생겼다고 해 볼게요.

src/
├── main.rs use inventory::count_items; ← `mod inventory;` 없음
└── inventory.rs pub fn count_items() -> u32 { 42 }

rustc는 무엇이 빠졌는지 정확히 말해 줘요.

error[E0432]: unresolved import `inventory`
--> src/main.rs:1:5
|
1 | use inventory::count_items;
| ^^^^^^^^^ use of unresolved module or unlinked crate `inventory`
|
help: to make use of source file src/inventory.rs, use `mod inventory` in this file to declare the module
|
1 + mod inventory;
|

help는 “src/inventory.rs 파일을 쓰려면 이 파일에서 mod inventory로 모듈을 선언하라”는 뜻이에요. src/main.rs(모듈이 라이브러리에 속한다면 src/lib.rs) 맨 위에 mod inventory;를 추가하세요. 대신 use crate::inventory::count_items;라고 써도 소용없어요. 모듈이 여전히 선언되지 않았으니 could not find `inventory` in the crate root(크레이트 루트에서 inventory를 찾을 수 없음)로 실패해요.

Playground에서는 모든 코드가 한 파일에 들어가니까, 여기서는 모듈을 mod inventory { ... }처럼 안에 바로 적었어요. 파일을 따로 나눈 것과 똑같이 동작해요.

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

실행 결과:

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

각 모듈은 부모에서 한 번만 선언하세요. 다른 파일에서는 use crate::inventory::...로 접근하면 돼요. 모듈을 쓰는 파일마다 mod inventory;를 넣지는 마세요.

방법 4: 올바른 곳에서 경로 시작하기

섹션 제목: “방법 4: 올바른 곳에서 경로 시작하기”

가져오는 줄이 어떤 모듈 안에 있고, 가져올 항목은 내 크레이트의 다른 모듈에 있을 때 이 방법을 고르세요. 여기서는 shop 안에 있는 receipt가 shop::store_name을 쓰고 싶어 해요.

mod shop {
pub fn store_name() -> &'static str {
"Ferris Fruits"
}
pub mod receipt {
use store_name; // ❌ 엉뚱한 곳에서 찾아요
pub fn header() -> String {
format!("== {} ==", store_name())
}
}
}
error[E0432]: unresolved import `store_name`
--> src/main.rs:7:13
|
7 | use store_name; // ❌ 엉뚱한 곳에서 찾아요
| ^^^^^^^^^^ no external crate `store_name`

“store_name이라는 외부 크레이트가 없다”는 뜻이에요. use 경로 맨 앞에 이름만 덩그러니 있으면 “크레이트, 또는 바로 이 모듈 안에서 선언한 것”을 뜻해요. store_name은 둘 다 아니라서, Rust는 그 이름의 크레이트를 찾았어요. 대신 어디서 시작할지 알려 주세요.

접두사 시작하는 곳 예
crate:: 내 크레이트의 루트(main.rs 또는 lib.rs) use crate::shop::prices::price_of;
super:: 부모 모듈 use super::store_name;
self:: 현재 모듈 use self::lines::line;

세 가지를 한 프로그램에서 모두 써 볼게요.

mod shop {
pub fn store_name() -> &'static str {
"Ferris Fruits"
}
pub mod prices {
pub fn price_of(item: &str) -> u32 {
if item == "apple" { 3 } else { 5 }
}
}
pub mod receipt {
use super::store_name; // 부모 모듈: shop
use crate::shop::prices::price_of; // 크레이트 루트에서 시작
use self::layout::line; // 이 모듈의 자식
mod layout {
pub fn line(item: &str, price: u32) -> String {
format!("{item}: {price}")
}
}
pub fn print(item: &str) {
println!("== {} ==", store_name());
println!("{}", line(item, price_of(item)));
}
}
}
fn main() {
shop::receipt::print("apple");
}

실행 결과:

== Ferris Fruits ==
apple: 3
▶ 직접 실행해 보기

여기서는 use layout::line;이라고 써도 동작해요. layout이 현재 모듈 안에서 선언됐기 때문이에요. self::는 그걸 분명하게 드러낼 뿐이에요. 헷갈릴 때는 crate::로 시작하는 전체 경로를 쓰세요. 내 크레이트 어디에서든 항상 통하고, rustc도 자주 help: a similar path exists(비슷한 경로가 있음) 뒤에 crate:: 버전을 제안해요.

예전 버전의 크레이트를 기준으로 쓴 코드. 많은 튜토리얼이 rand 0.8을 써요. rand 0.10에서는 이런 에러가 나요.

error[E0432]: unresolved import `rand::thread_rng`
--> src/main.rs:1:5
|
1 | use rand::thread_rng;
| ^^^^^^^^^^^^^^^^ no `thread_rng` in the root

“루트에 thread_rng가 없다”는 뜻이에요. 해결: docs.rs에서 Cargo.toml에 적힌 버전의 문서를 확인하세요. 여기서는 새 이름이 rand::rng()예요. 난수를 참고하세요.

main.rs와 lib.rs가 둘 다 있는 패키지. 이 둘은 서로 다른 크레이트예요. main.rs 안에서 crate::는 바이너리 크레이트를 뜻해요. 그래서 lib.rs에 pub mod inventory;가 있어도 use crate::inventory::count_items;는 could not find `inventory` in the crate root로 실패해요. 해결: 패키지 이름을 쓰세요. use shop_app::inventory::count_items;처럼요(대시는 밑줄로 바꿔요).

항목은 있는데 비공개일 때. 이건 E0432가 아니라 다른 에러인 E0603이에요.

error[E0603]: function `count_items` is private
--> src/main.rs:7:16
|
7 | use inventory::count_items;
| ^^^^^^^^^^^ private function

“함수 count_items가 비공개(private)“라는 뜻이에요. 해결: fn 앞에 pub을 붙이세요. 경로에 있는 mod 앞에도 붙여야 해요. 모듈이 비공개면 module `prices` is private가 나오거든요. 모듈을 참고하세요.

  • E0433: 코드 안의 경로(HashMap::new()나 rand::rng() 같은)를 해석할 수 없어요. 원인은 같지만 use 줄이 아닌 곳에서 나요.
  • E0425: 값이나 함수를 찾을 수 없어요. 같은 use 줄로 고쳐질 때가 많아요.
  • E0603: 가져올 항목은 찾았지만 비공개예요. pub을 붙이세요.
  • E0463: can't find crate(크레이트를 찾을 수 없음). 크레이트가 Cargo.toml에 없는데 extern crate rand;를 쓰면 나요.
  • 전체 컴파일러 에러: 에러 페이지 전체 목록이에요.

이해도 점검

1. 새 프로젝트에 use serde::Serialize;를 복사했더니, 크레이트 serde가 unresolved이거나 unlinked라는 E0432가 나요. 어떻게 고칠까요?

2. src/billing.rs를 만들었는데 main.rs의 use billing::total;이 실패해요. 무엇이 빠졌을까요?

3. mod shop { mod receipt { ... } } 안에서 receipt가 shop에 바로 정의된 함수를 가져오려면 어떻게 쓸까요?

점수: 0 / 3