Rust는 조직화된 방식으로 코드의 재사용을 도와주는 모듈(module)을 갖추고 있습니다. 코드 몇 줄을 함수로 추출하는 것과 같은 방식으로, 함수(혹은 구조체나 열거형 같은 다른 코드들)를 다른 모듈로 뽑아낼 수 있으며 이들을 public 혹은 private으로 정의할 수 있습니다.
mod
: 새로운 모듈 선언pub
: 기본적으로 함수, 타입, 상수, 모듈은 모두 private이기 때문에 pub
키워드를 통해 public 선언use
: 모듈이나 모듈 내의 정의들을 스코프 안으로 가져와서 쉽게 참조 가능하도록 함먼저 cargo를 이용해 binary crate를 만드는 대신에 library crate를 만듭니다. library crate란 다른 사람들이 자신들의 프로젝트에 dependency로 추가할 수 있는 프로젝트를 말합니다.
$ cargo new communicator --lib
$ cd communicator
cargo가 src/main.rs 대신 src/lib.rs 를 생성했으며 내부에는 아래와 같은 코드를 찾을 수 있습니다.
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
}
}
cargo는 우리가 만든 라이브러리의 작성 시작을 돕기 위해 빈 테스트를 만드는데, 이는 --bin
옵션을 사용했을 때 "Hello, world!" 바이너리를 만들어준 것과 사뭇 다릅니다.
src/main.rs 파일이 없기 때문에 cargo run
커맨드로 cargo가 실행할 것이 없습니다. 따라서 여기서는 library crate 코드를 컴파일하기 위해 cargo build
를 사용할 것입니다.
communicator
네트워크 라이브러리를 위해 먼저 connect
라는 이름의 함수가 정의되어 있는 network
라는 이름의 모듈을 정의합니다. Rust 내 모듈 정의는 모두 mod
로 시작됩니다. 아래의 코드를 src/lib.rs 의 테스트 코드 윗 쪽에 추가합니다.
mod network {
fn connect() {
}
}
같은 파일 내에 여러 개의 모듈을 나란히 정의할 수도 있습니다.
mod network {
fn connect() {
}
}
mod client {
fn connect() {
}
}
모듈 안에 다른 모듈을 집어넣는 것도 가능합니다.
mod network {
fn connect() {
}
mod client {
fn connect() {
}
}
}
Filename: src/lib.rs
mod client {
fn connect() {
}
}
mod network {
fn connect() {
}
mod server {
fn connect() {
}
}
}
위의 코드에서 client
모듈의 코드를 선언 부분만 남겨둡니다.
mod client;
mod network {
fn connect() {
}
mod server {
fn connect() {
}
}
}
여전히 client
모듈을 선언하고 있지만 코드 블록을 세미콜론으로 대체함으로써 Rust에게 client
모듈의 스코프 내에 정의된 코드를 다른 위치에서 찾으라고 말하게 됩니다. 달리 말하자면 mod client;
의 뜻은 아래와 같습니다.
mod client {
// contents of client.rs
}
이제 모듈의 이름과 같은 이름을 가지는 외부 파일을 만듭니다.
Filename: src/client.rs
fn connect() {
}
이미 src/lib.rs 안에 client
모듈을 선언했기 때문에 이 파일 안에서 mod
선언이 필요하지 않습니다.
동일한 방식으로 network
모듈을 개별 파일로 추출합니다.
Filename: src/lib.rs
mod client;
mod network;
Filename: src/network.rs
fn connect() {
}
mod server {
fn connect() {
}
}
이제 몇몇 컴파일 경고가 생기지만 프로젝트는 성공적으로 컴파일되어야 합니다. cargo run
이 아닌 cargo build
를 이용해야합니다.
서브모듈을 추출하는 것은 위의 방법과 조금 다릅니다.
이에 대응하는 파일 레이아웃은 아래와 같이 생겼습니다:
├── src
│ ├── client.rs
│ ├── lib.rs
│ └── network
│ ├── mod.rs
│ └── server.rs
Filename: src/network/mod.rs
fn connect() {
}
mod server;
Filename: src/network/server.rs
fn connect() {
}
다시 cargo build
를 실행하면 여전히 경고는 발생하지만 성공적으로 컴파일됩니다.