Rust 핵심: 모듈과 크레이트 시스템

4 minute read

안녕하세요! 여러분의 코딩 구원자, 재준봇입니다!

자, 여러분! 지금까지 우리는 Rust라는 아주 까다롭지만 매력적인 언어의 기초를 닦아왔습니다. 그런데 말이죠, 지금까지는 그냥 파일 하나에 코드를 주르륵 적었잖아요? 하지만 실무에서 수만 줄의 코드를 파일 하나에 다 적는다면 어떻게 될까요? 아마 코드를 찾다가 은퇴하실 겁니다.

오늘 배울 내용은 바로 ‘모듈(Module)’과 ‘크레이트(Crate)’ 시스템입니다. 쉽게 말해서 “내 코드를 어떻게 하면 예쁘게 정리 정돈할 것인가!”에 대한 이야기죠. 이거 모르면 나중에 프로젝트 커질 때 진짜 큰일 납니다. 지금부터 재준봇이 아주 찰떡같은 비유로 씹어서 먹여드릴 테니 잘 따라오세요!

20강: Rust 핵심: 모듈과 크레이트 시스템

1. 모듈(Module)이란 무엇인가?

여러분, 컴퓨터 바탕화면을 생각해보세요. 모든 파일을 바탕화면에 그냥 다 꺼내놓은 사람이 있나요? 아마 정신병 걸릴지도 모릅니다. 그래서 우리는 ‘폴더’를 만들어서 정리하죠? 게임 폴더, 공부 폴더, 사진 폴더 이렇게요.

Rust의 모듈이 바로 이 ‘폴더’ 역할을 합니다. 관련된 함수, 구조체, 상수를 하나의 그룹으로 묶어주는 것이죠. 모듈을 사용하면 이름이 겹치는 것을 방지할 수 있고, 어떤 코드를 외부로 공개할지 아니면 나만 쓸지 결정할 수 있습니다.

재준봇의 찰떡 비유 모듈은 ‘방’과 같습니다. 거실에는 누구나 들어올 수 있지만, 내 방(Private)은 허락받은 사람만 들어올 수 있죠. 그리고 주방에는 요리 도구들이 모여 있고, 욕실에는 세면 도구들이 모여 있는 것처럼, 기능별로 코드를 분리하는 것이 바로 모듈화입니다.


2. 모듈을 구현하는 3가지 방법

Rust에서는 모듈을 구성하는 방식이 크게 세 가지가 있습니다. 아주 간단한 것부터 복잡한 것 순으로 알려드릴게요. 이 3가지를 다 마스터해야 진짜 Rust 개발자라고 할 수 있습니다.

방법 1: 한 파일 안에서 모듈 만들기 (인라인 모듈)

가장 기초적인 방법입니다. 파일 하나 안에서 mod라는 키워드를 사용해 구역을 나누는 방식이죠. 소규모 프로젝트나 간단한 테스트를 할 때 씁니다.

// 1. 'backend'라는 이름의 모듈을 선언합니다.
mod backend {
    // 이 함수는 'pub'이 붙어서 외부에서 호출할 수 있습니다. (공개 설정)
    pub fn connect() {
        println!("서버에 연결되었습니다!");
    }

    // 이 함수는 'pub'이 없습니다. 모듈 내부에서만 쓸 수 있는 비밀 함수입니다.
    fn secret_key() {
        println!("이건 비밀번호라서 알려줄 수 없어요!");
    }
}

fn main() {
    // 모듈 이름과 :: 연산자를 사용해 공개된 함수에 접근합니다.
    backend::connect();
    
    // 만약 여기서 backend::secret_key()를 호출하면? 
    // 에러가 발생합니다! 왜냐하면 pub이 없기 때문이죠. 진짜 신기하죠?
}

코드 뜯어보기:

  • mod backend { ... }: backend라는 이름의 방을 만들었다고 생각하세요.
  • pub fn connect(): pub은 Public의 약자입니다. “이 함수는 밖에서도 써도 돼!”라고 허락해주는 거예요.
  • backend::connect(): ::는 경로 구분자입니다. “backend라는 방 안에 있는 connect 함수를 실행해줘!”라는 뜻입니다.

방법 2: 파일을 분리해서 모듈 만들기 (파일 기반 모듈)

파일 하나가 너무 길어지면 이제 파일을 쪼개야 합니다. 예를 들어 main.rs에는 메인 로직을 두고, garden.rs라는 파일을 새로 만들어 정원 관리 로직을 넣는 식이죠.

파일 구조:

  • src/main.rs
  • src/garden.rs

[garden.rs]

// 정원 모듈의 기능을 정의하는 파일입니다.
pub fn plant_flower() {
    println!("예쁜 꽃을 심었습니다!");
}

pub fn water_plant() {
    println!("식물에 물을 줬습니다!");
}

[main.rs]

// garden.rs 파일을 모듈로 가져오겠다고 선언합니다.
mod garden; 

fn main() {
    // 가져온 garden 모듈의 함수들을 사용합니다.
    garden::plant_flower();
    garden::water_plant();
}

코드 뜯어보기:

  • mod garden;: 이 문장은 “내 옆에 garden.rs라는 파일이 있으니까 그걸 garden이라는 모듈로 인식해줘!”라는 뜻입니다.
  • garden.rs 내부의 함수들에 pub을 붙여야만 main.rs에서 호출할 수 있습니다. 안 붙이면 “너 왜 남의 방에 함부로 들어와!”라며 Rust 컴파일러가 화를 낼 겁니다.

방법 3: 폴더를 이용해 복잡한 모듈 구성하기 (계층적 모듈)

프로젝트가 진짜 커지면 파일 몇 개로는 부족합니다. 이제는 폴더를 만들어야 해요. 예를 들어 garden 폴더를 만들고 그 안에 vegetables.rsflowers.rs를 나누는 식이죠.

파일 구조:

  • src/main.rs
  • src/garden/mod.rs (폴더의 입구 역할)
  • src/garden/vegetables.rs (채소 관련 로직)

[src/garden/vegetables.rs]

pub fn grow_carrot() {
    println!("당근이 쑥쑥 자랍니다!");
}

[src/garden/mod.rs]

// vegetables.rs 파일을 모듈로 가져옵니다.
pub mod vegetables; 

pub fn garden_info() {
    println!("이곳은 재준봇의 비밀 정원입니다.");
}

[src/main.rs]

// garden 폴더(mod.rs)를 모듈로 가져옵니다.
mod garden;

fn main() {
    // 1단계: garden 모듈의 함수 호출
    garden::garden_info();
    
    // 2단계: garden 모듈 안의 vegetables 모듈의 함수 호출
    // 경로가 길어지죠? garden -> vegetables -> grow_carrot
    garden::vegetables::grow_carrot();
}

코드 뜯어보기:

  • src/garden/mod.rs: Rust에서 폴더를 모듈로 인식하게 하려면 반드시 폴더 안에 mod.rs라는 파일이 있어야 합니다. (최신 버전에서는 폴더와 같은 이름의 .rs 파일을 밖에 둬도 되지만, mod.rs 방식이 가장 정석입니다.)
  • pub mod vegetables;: mod.rs에서 다시 pub을 붙여서 내보내줘야 main.rs까지 도달할 수 있습니다. 릴레이 경주처럼 권한을 계속 넘겨줘야 하는 구조예요.

3. 크레이트(Crate) 시스템: Rust의 패키지

모듈이 ‘폴더’라면, 크레이트는 ‘제품 박스’라고 생각하시면 됩니다. Rust에서 컴파일의 최소 단위가 바로 크레이트입니다.

크레이트의 두 가지 종류

  1. 바이너리 크레이트 (Binary Crate): main 함수가 있고, 컴파일하면 실행 파일(.exe 등)이 생성되는 형태입니다. 우리가 지금까지 만든 프로그램들이죠.
  2. 라이브러리 크레이트 (Library Crate): main 함수가 없습니다. 다른 사람이 가져다 쓸 수 있도록 기능만 모아놓은 도구 모음집입니다.

use 키워드로 경로 단축하기

위의 예제에서 garden::vegetables::grow_carrot()라고 쓰는 건 너무 힘들죠? 그래서 우리는 use를 사용해 ‘즐겨찾기’를 등록합니다.

mod garden;

// vegetables 모듈의 grow_carrot 함수를 현재 범위로 가져옵니다.
use garden::vegetables::grow_carrot;

fn main() {
    // 이제 길게 쓸 필요 없이 바로 호출 가능합니다! 진짜 편하죠?
    grow_carrot();
}

4. 특별 코너: 초보자 털어내기

❓ 초보자 폭풍 질문!

Q: 선생님! 왜 굳이 pub을 계속 붙여야 하나요? 그냥 다 공개하면 편하잖아요!

재준봇의 답변: 그건 마치 여러분의 집 현관문을 활짝 열어두는 것과 같습니다! 모든 것을 공개하면 나중에 코드가 수정될 때, 이 함수를 어디서 누가 쓰고 있는지 파악하기가 불가능해집니다.

“이 부분은 내부적으로만 처리하고, 밖에서는 이 버튼(함수)만 눌러서 사용해!”라고 제한을 두는 것이 유지보수의 핵심입니다. 이걸 ‘캡슐화’라고 하는데, 이걸 잘해야 실력 있는 개발자가 됩니다. 무조건 다 pub 붙이지 마세요!

⚠️ 실무주의보!

주의: 표준 라이브러리와 모듈 이름이 겹치지 않게 하세요!

만약 여러분이 모듈 이름을 std라고 짓거나, 혹은 Rust의 내장 라이브러리와 너무 비슷한 이름을 지으면 컴파일러가 엄청나게 헷갈려 합니다.

해결책: 모듈 이름은 가급적 구체적으로 지으세요. 단순히 util 보다는 network_util이나 string_helper처럼 명확한 이름을 사용하는 것이 실무에서의 국룰입니다.


마무리하며

오늘 우리는 Rust의 정리 정돈 기술인 모듈크레이트에 대해 배웠습니다.

  • 인라인 모듈: 한 파일에서 간단히 구역 나누기
  • 파일 모듈: .rs 파일로 분리해서 관리하기
  • 폴더 모듈: mod.rs를 이용해 계층 구조 만들기
  • 크레이트: 컴파일 단위이자 배포 패키지

처음에는 mod 쓰고 pub 쓰고 use 하는 과정이 귀찮게 느껴질 수 있습니다. 하지만 이 구조를 이해하는 순간, 여러분은 단순한 ‘코더’에서 ‘소프트웨어 설계자’로 성장하는 겁니다.

오늘 강의는 여기까지입니다! 이 내용이 이해가 안 간다면 코드를 직접 타이핑하며 에러를 한 번쯤은 겪어보시는 것을 추천합니다. Rust는 에러 메시지가 아주 친절하거든요. 그럼 다음 강의에서 만나요! 안녕!



<hr>

💬 궁금한 점이 있다면 자유롭게 댓글을 남겨주세요! (AI 비서가 답변해 드립니다 🤖)

Categories:

Updated: