동작하는 코드
코드가 점점 길어지면, 하나의 파일에 모든 걸 넣기 어려워져요. 모듈(module) 로 코드를 정리할 수 있어요.
mod math {
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn multiply(a: i32, b: i32) -> i32 {
a * b
}
fn secret_formula(x: i32) -> i32 {
x * 42 // 비공개 함수!
}
}
fn main() {
let sum = math::add(3, 5);
let product = math::multiply(4, 6);
println!("3 + 5 = {sum}");
println!("4 x 6 = {product}");
// math::secret_formula(1); // 에러! 비공개
}
mod math로 모듈을 만들고, math::add()처럼 경로를 써서 호출해요.
직접 수정하기
math::secret_formula(1)주석을 풀어보세요. 어떤 에러가 나나요?secret_formula에pub을 붙이면 에러가 사라지나요?
"왜?" — pub과 비공개 기본값
Rust에서 모듈 안의 항목은 기본적으로 비공개예요. 외부에서 사용하려면 pub을 명시적으로 붙여야 해요.
이건 소유권 철학과 같은 맥락이에요 — 안전이 기본값이에요. 필요한 것만 공개하고, 나머지는 숨기는 게 좋은 습관이에요.
| 키워드 | 의미 |
| ------ | ------------------------------------- |
| (없음) | 비공개 — 같은 모듈 안에서만 접근 가능 |
| pub | 공개 — 외부에서도 접근 가능 |
use — 경로를 짧게
math::add() 대신 더 짧게 쓰고 싶으면 use를 사용해요.
mod math {
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn multiply(a: i32, b: i32) -> i32 {
a * b
}
}
use math::add;
use math::multiply;
fn main() {
println!("3 + 5 = {}", add(3, 5));
println!("4 x 6 = {}", multiply(4, 6));
}
여러 개를 한 번에 가져올 수도 있어요.
use math::{add, multiply};
모듈을 파일로 분리하기
코드가 더 커지면 모듈을 별도 파일로 분리해요. 실제 프로젝트에서 가장 많이 쓰는 패턴이에요.
src/
├── main.rs
└── math.rs
src/math.rs:
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn multiply(a: i32, b: i32) -> i32 {
a * b
}
src/main.rs:
mod math; // math.rs 파일을 모듈로 가져옴
fn main() {
println!("3 + 5 = {}", math::add(3, 5));
}
mod math;만 쓰면 Rust가 알아서 math.rs 파일을 찾아서 연결해줘요.
외부 크레이트 사용하기
모듈 07에서 rand 크레이트를 사용한 적 있죠? 외부 크레이트는 crates.io에서 찾을 수 있어요.
cargo add rand
이 명령어가 Cargo.toml의 [dependencies]에 자동으로 추가해줘요.
[dependencies]
rand = "0.8"
그 다음 use로 가져와서 사용하면 돼요.
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
let number: i32 = rng.gen_range(1..=100);
println!("랜덤 숫자: {number}");
}
표준 라이브러리 모듈
Rust에는 자주 쓰는 기능이 표준 라이브러리(std) 에 들어있어요. 별도 설치 없이 use로 가져오면 돼요.
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("민수", 95);
scores.insert("지수", 88);
for (name, score) in &scores {
println!("{name}: {score}점");
}
}
자주 쓰는 표준 라이브러리 모듈이에요.
| 모듈 | 용도 |
| ------------------ | -------------------- |
| std::io | 입출력 |
| std::collections | HashMap, BTreeMap 등 |
| std::fs | 파일 읽기/쓰기 |
| std::fmt | 포맷팅 |
더 알아보기: crates.io에서 크레이트 찾기
crates.io는 Rust 패키지 저장소예요. 수만 개의 크레이트가 있어요.
인기 있는 크레이트 몇 가지를 소개할게요.
| 크레이트 | 용도 |
| --------- | ------------------------------ |
| serde | JSON 등 데이터 직렬화/역직렬화 |
| tokio | 비동기 런타임 |
| clap | 커맨드라인 인자 파싱 |
| reqwest | HTTP 요청 |
크레이트를 고를 때는 다운로드 수와 최근 업데이트 날짜를 확인하세요. 활발히 관리되는 크레이트를 사용하는 게 좋아요.
더 알아보기: 모듈 경로와 crate 키워드
모듈 경로에는 두 가지 시작점이 있어요.
// 절대 경로: crate부터 시작
crate::math::add(1, 2);
// 상대 경로: 현재 위치부터
math::add(1, 2);
// 부모 모듈 참조
super::some_function();
crate는 현재 프로젝트의 루트를 가리키는 키워드예요. 큰 프로젝트에서 경로가 복잡해지면 절대 경로가 명확해요.
연습 1. geometry 모듈을 만들고, circle_area와 rectangle_area 함수를 추가해보세요.
mod geometry {
// circle_area: 반지름을 받아서 원의 넓이 반환
// rectangle_area: 가로, 세로를 받아서 직사각형 넓이 반환
// 둘 다 pub으로!
// 힌트: PI는 std::f64::consts::PI
}
fn main() {
println!("원: {:.2}", geometry::circle_area(5.0));
println!("사각형: {:.2}", geometry::rectangle_area(4.0, 6.0));
}
연습 2. use를 사용해서 아래 코드를 더 짧게 바꿔보세요.
fn main() {
let mut map = std::collections::HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
let mut set = std::collections::HashSet::new();
set.insert("x");
set.insert("y");
println!("{:?}", map);
println!("{:?}", set);
}
힌트: use std::collections::{HashMap, HashSet};
Q1. Rust에서 모듈 안의 함수는 기본적으로?
- A) 공개(public)이다
- B) 비공개(private)이다
- C) 읽기 전용이다
- D) 상수(const)이다
Q2. 외부 크레이트를 프로젝트에 추가하는 명령어는?
- A)
cargo install 크레이트 - B)
cargo add 크레이트 - C)
cargo get 크레이트 - D)
cargo import 크레이트
Q3. 아래 코드에서 에러가 나는 이유는?
mod secrets {
fn hidden() -> i32 { 42 }
}
fn main() {
println!("{}", secrets::hidden());
}
- A)
mod문법이 잘못되었다 - B)
hidden함수가 비공개이다 - C) 반환 타입이 잘못되었다
- D)
secrets모듈이 존재하지 않는다