← Rust 강의 목록으로
🦀
모던 Rust
모던 · 선수: 에러 처리 1~4강

19. 모듈 시스템·Cargo·crates.io

Rust 프로젝트가 커지면 코드를 모듈로 나누고 외부 크레잇을 끌어다 씁니다. 이 강의에서 mod 키워드와 파일 분할 규칙, pub 가시성, use 경로, Cargo.toml 의 의존성 명시, 그리고 crates.io 에서 패키지를 찾고 추가하는 흐름까지 한 번에 정리합니다.

RustmoduleCargocratecrates.iopubuse
소요 시간
약 1.5시간
난이도
📊 중급
선수 조건
🎯 에러 처리 1~4강
결과물
Rust 프로젝트가 커지면 코드를 모듈로 나누고 외부 크레잇을 끌어다 씁니다. 이 강의에서 mod 키워드와 파일 분할 규칙, pub 가시성, use 경로, Cargo.toml 의 의존성 명시, 그리고 crates.io 에서 패키지를 찾고 추가하는 흐름까지 한 번에 정리합니다.

이 강의에서 배우는 것

  • 1mod 로 코드를 모듈로 분할한다
  • 2pub 키워드로 가시성을 제어한다
  • 3use 로 경로를 짧게 줄인다
  • 4Cargo.toml 의 [dependencies] 에 외부 크레잇을 추가한다
  • 5cargo add / cargo search / cargo doc 으로 패키지 작업을 한다

소개

main.rs 한 파일에 모든 코드를 몰아 두면 100줄을 넘기는 순간 가독성이 빠르게 떨어집니다. Rust 는 한 파일 = 한 모듈 식의 간단한 규칙으로 코드 분할을 강제 없이 자연스럽게 풀어줍니다.

핵심 개념

1) crate / module 구분

  • **crate** — Cargo.toml 한 개 단위 (== 패키지 = 빌드 단위)
  • **module** — 한 crate 안의 네임스페이스 단위
  • binary crate 의 root = `src/main.rs`, library crate 의 root = `src/lib.rs`

2) mod 와 파일 분할

rust
// src/main.rs
mod math;       // math.rs 또는 math/mod.rs 를 찾음

fn main() {
    println!("{}", math::add(2, 3));
}

// src/math.rs
pub fn add(a: i32, b: i32) -> i32 { a + b }

3) pub — 가시성 제어

  • 기본은 **private** (같은 모듈 안에서만)
  • `pub` — 외부 공개
  • `pub(crate)` — 같은 crate 안에서만 공개
  • `pub(super)` — 부모 모듈에만

4) use — 경로 단축

rust
use std::collections::HashMap;
use std::io::{self, Read};       // self = io 자체, Read = trait
use crate::math::add as plus;     // 별칭

5) Cargo.toml 의존성

toml
[dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
thiserror = "1"

핵심 예제

디렉토리 구조 예:

bash
src/
├── main.rs
├── config.rs
└── api/
    ├── mod.rs       (또는 src/api.rs)
    ├── user.rs
    └── post.rs
rust
// src/main.rs
mod config;
mod api;

fn main() {
    let cfg = config::load();
    api::user::create(&cfg);
}

// src/api/mod.rs (또는 src/api.rs + src/api/ 폴더)
pub mod user;
pub mod post;

// src/api/user.rs
use crate::config::Config;
pub fn create(cfg: &Config) { /* ... */ }

외부 크레잇 추가·사용:

bash
cargo add serde --features derive
cargo add chrono
cargo search regex      # crates.io 검색
rust
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
struct User { name: String, age: u32 }

fn main() {
    let u = User { name: "홍길동".into(), age: 30 };
    let json = serde_json::to_string(&u).unwrap();
    println!("{}", json);
}

자주 하는 실수

Q. mod 와 use 의 차이가 뭐죠?

A. **mod** 는 모듈을 "존재시키는" 선언, **use** 는 이미 존재하는 경로를 "짧게 가져오는" 선언입니다. mod foo; 를 안 쓰면 use crate::foo 도 못 합니다.

Q. pub 안 붙이면 같은 파일에서도 못 쓰나요?

A. 같은 모듈(=같은 파일·같은 mod 블록) 안에서는 pub 없이도 접근 가능. **외부 모듈에서 접근하려면 pub 필수**.

Q. Cargo.lock 은 git 에 올리나요?

A. **바이너리 crate 는 올리고, 라이브러리 crate 는 올리지 않습니다.** 바이너리는 재현 가능한 빌드가 중요하고, 라이브러리는 사용자의 lockfile 이 별도라 의미가 없습니다.

정리

  • crate = 빌드 단위, module = 네임스페이스 단위
  • mod 로 선언, 파일/폴더 규칙으로 자동 매핑
  • pub / pub(crate) / pub(super) 로 가시성 제어
  • use 로 경로 단축, Cargo.toml 에 의존성, cargo add 로 추가

과제

  1. main.rs + math.rs 로 분할하고 main 에서 math::add 호출
  2. src/api/ 폴더에 user.rs / post.rs 모듈을 만들고 main 에서 사용
  3. cargo add chrono 로 chrono 추가 후 현재 시각을 출력
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗