10편 이후부터는 프로젝트가 빠르게 비대해집니다. 함수와 구조체가 한 파일에 모여 있으면 ownership 규칙을 추적하기 어려워지므로, Rust가 제공하는 모듈·패키지 시스템으로 코드를 분해하는 훈련이 필요합니다.
전체 그림: crate, package, module
- package:
Cargo.toml이 위치한 최상위 단위로, 하나 이상의 crate를 포함합니다. 대부분의 입문 예제는 하나의 binary crate만 포함합니다. - crate: 컴파일러가 독립적으로 빌드하는 단위입니다.
src/main.rs는 binary crate,src/lib.rs는 library crate의 진입점이 됩니다. - module (
mod): crate 내부에서 코드를 논리적으로 그룹화하는 단위입니다. 파일이나mod블록으로 선언할 수 있습니다.
한 줄 그림으로 보면 아래와 같습니다.
package 안에 하나 이상 crate가 있고, 각 crate 안에 여러 module이 들어갑니다.
단일 파일 모듈 선언
처음에는 src/main.rs 안에서 mod 블록을 사용해 작은 단위부터 나눌 수 있습니다.
mod auth {
pub fn login(user: &str) {
println!("{} 로그인", user);
}
}
fn main() {
auth::login("yuna");
}
mod auth { ... }는auth라는 모듈을 만듭니다.- 모듈 밖에서 사용할 함수는
pub으로 공개해야 합니다. ::연산자를 사용해 모듈 경로를 따라 접근합니다.
파일로 모듈 분리하기
코드가 길어지면 파일 분리가 필요합니다. Rust는 mod foo; 선언을 만나면 foo.rs 또는 foo/mod.rs 파일을 찾습니다.
src/
├── main.rs
├── auth.rs
└── user/
├── mod.rs
└── profile.rs
main.rs에서 아래와 같이 선언합니다.
mod auth;
mod user;
fn main() {
auth::login("yuna");
user::profile::show("yuna");
}
user/mod.rs에서는 하위 모듈을 다시 선언합니다.
pub mod profile;
pub fn list() {
println!("사용자 목록");
}
- 디렉터리 기반 모듈은
mod.rs(새로운 에디션에서는mod.rs대신user.rs+user/profile.rs로도 구성 가능) 파일을 통해 하위 모듈을 노출합니다. pub mod profile;은profile.rs파일을 포함시키고 외부에서도 접근할 수 있게 만듭니다.
즉, user/mod.rs 안에 pub mod profile;이 있으면 Rust는 보통 user/profile.rs 파일을 찾는다고 이해하면 됩니다.
use로 경로 단축하기
긴 경로를 반복하지 않으려면 use를 활용합니다.
use crate::auth::login;
use crate::user::profile::show;
fn main() {
login("yuna");
show("yuna");
}
crate::는 현재 crate의 루트를 가리킵니다.super::는 한 단계 상위 모듈을,self::는 현재 모듈을 가리킵니다.use crate::user::{profile, list};처럼 중괄호를 사용하면 동일한 경로에서 여러 항목을 불러올 수 있습니다.
참고로 use는 경로를 짧게 쓰게 해 주는 가져오기일 뿐, 다른 모듈에 다시 공개하는 것은 아닙니다. 외부에 다시 노출하려면 pub use를 사용합니다.
공개 범위 설계하기
Rust 모듈 시스템의 핵심은 "무엇을 공개할지" 스스로 설계하는 것입니다.
pub(crate)으로 동일 crate 내부에만 공개할 수 있습니다.pub(super)는 상위 모듈까지만 공개합니다.- 내부 구현(예: 데이터베이스 어댑터)은 비공개로 두고, 필요한 API만
pub으로 외부에 노출하세요.
Cargo workspace 살짝 맛보기
프로젝트가 커지면 여러 crate를 묶는 workspace가 필요할 수 있습니다. 이번 편에서는 구조만 가볍게 살펴봅니다.
[workspace]
- 루트
Cargo.toml에workspace를 선언하고, 각 멤버 crate는 자신의Cargo.toml을 가집니다. cargo build -p app처럼 특정 crate만 빌드할 수 있어 모듈 경계가 더 명확해집니다.
CodeSandbox로 이어서 실습하기
아래 샌드박스는 CodeSandbox의 Rust starter입니다. 이번 글의 핵심 코드를 src/main.rs에 옮기고, cargo check와 cargo run 결과를 나란히 보면서 컴파일 메시지와 실행 출력을 비교해 보세요.
💬 댓글
이 글에 대한 의견을 남겨주세요