프로젝트 규모가 커지면 코드를 여러 모듈, 파일로 나눠서 관리해야 합니다. 한 패키지는 여러 개의 바이너리 크레이트와 라이브러리 크레이트를 포함할 수 있고, 커진 프로젝트의 각 부분을 크레이트로 나눠서 외부 라이브러리처럼 쓸 수 있습니다.
러스트에서 코득 조직화에 필요로하는 모듈 시스템에는 다음과 같은 기능들이 있습니다.
- 패키지 : 크레이트를 빌드, 테스트, 공유하는 데 사용하는 카고 기능
- 크레이트 : 라이브러리나 실행 가능한 모듈로 구성된 트리 구조
- 모듈과 use : organization, scope를 제어하고, 조직 세부 경로를 감추는 데 사용
- 경로 : 구조체, 함수, 모듈 등의 이름을 지정
<패키지와 크레이트>
- 크레이트(crate) : 러스트가 컴파일 한 차례에 고려하는 가장 작은 코드 단위입니다. 크레이트는 여러 모듈을 담을 수 있고, 모듈은 이 크레이트와 함께 컴파일되는 다른 파일들에 정의될 수 있습니다.
크레이트에는 바이너리와 라이브러리가 있습니다.
- 바이너리 크레이트(binary crate) : 실행파일로 컴파일할 수 있는 프로그램입니다. 바이너리 크레이트는 main 함수를 포함하고 있어야 합니다.
- 라이브러리 크레이트(library crate) : main 함수를 가지고 있지 않고, 실행 파일 형태로 컴파일되지 않습니다. 대신 여러 프로젝트에서 공용으로 사용될 기능들이 정의되어 있습니다.
- 크레이트 루트(crate root) : 러스트 컴파일러가 컴파일러를 시작하는 소스 파일로, 크레이트의 루트 모듈을 구성합니다.
- 패키지(package) : 일련의 기능을 제공하는 하나 이상의 크레이트로 구성된 번들입니다. 패키지에는 해당 크레이트들을 빌드하는 법이 설명된 Cargo.toml 파일이 포함되어 있습니다. cargo도 커맨드 라인 도구의 바이너리 크레이트가 포함된 패키지입니다.
<모듈>
- 크레이트를 컴파일 할 때 컴파일러는 크레이트 루트를 먼저 봅니다. (라이브러리 크레이트의 경우 src/lib.rs, 바이너리 크레이트의 경우 src/main.rs)
- 모듈 : 크레이트 루트 파일에는 새로운 모듈을 선언할 수 있습니다.
mod garden; // garden이라는 모듈
- 서브모듈 : 크레이트 루트 외의 다른 파일에서 서브모듈을 선언할 수 있습니다.
- path : 모듈이 크레이트의 일부로서 공개되면, 공개 규칙이 허용하는 한도 내에서 해당 코드의 path를 사용해서 동일한 크레이트 어디서든 이 모듈의 코드를 참조할 수 있게 합니다.
crate::garden::vegetables::Asparagus // garden 모듈의 vegetables 모듈 안에 있는 Asparagus 타입
- pub : 모듈 내의 코드는 기본적으로 private입니다. 따라서 공개로 만들기 위해서는 mod 대신 pub mod로 선언해야 합니다.
- use : 어떤 스코프 내의 use 키워드는 긴 경로의 반복을 줄이기 위해 쓰입니다.
use crate::garden::vegetables::Asparagus;
// Asparagus만 작성하면 해당 타입 사용 가능
- 모듈은 크레이트의 코드를 읽고 재사용하기 쉽게 구조화할 수 있습니다. 다음은 예시를 위해 호스트와 서버 업무를 각각 다른 모듈로 나눈 코드입니다. hosting, serving은 front_of_house 모듈 내에 정의된 형제이고, front_of_house는 부모 모듈입니다.
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
pub fn seat_at_table() {}
}
pub mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
파일 시스템의 디렉토리처럼 모듈도 코드를 조직화합니다.
<path>
모듈 트리에서 아이템을 찾으려면 그 아이템의 경로를 알아야합니다.
경로는 다음과 같은 두 가지 형태가 있습니다.
- 절대 경로(absolute path) : 크레이트 루트로부터 시작되는 경로.
- 상대 경로(relative path) : 현재 모듈을 시작점으로 하는 경로. self, super, 현재 모듈 내의 식별자를 사용합니다.
절대 경로와 상대 경로 뒤에는 :: 으로 구분된 식별자가 하나 이상 붙습니다. 위의 예시에서 정의했던 front_of_house 모듈을 예시로 살펴보겠습니다. 해당 절대 경로를 front_of_house 모듈 밖에서 사용할 경우 front_of_house 모듈은 public이 아니기 때문에 에러가 발생합니다.
mod front_of_house { ... }
pub fn eat_at_restaurant() {
// 절대 경로
crate::front_of_house::hosting::add_to_waitlist();
// 상대 경로
front_of_house::hosting::add_to_waitlist();
}
아이템을 호출하는 코드와 정의하는 코드는 분리되어 있을 가능서이 높아 일반적으로는 절대 경로가 더 선호됩니다.
Tip) 모듈 트리는 src/lib.rs(라이브러리 크레이트의 루트) 내에 정의되어야 바이너리 크레이트 내에서 패키지 이름으로 시작하는 경로를 사용해 모든 public 아이템을 사용할 수 있습니다.
- super : super로 시작하면 현재 모듈 또는 크레이트 루트 대신, 본인의 부모 모듈로부터 시작되는 상대 경로를 만들 수 있습니다. 다음 코드의 super::deliver_order(); 은 back_of_house 모듈의 부모 모듈에서 경로를 시작합니다.
fn deliver_order() {}
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::deliver_order();
}
fn cook_order() {}
}
- 열거형의 경우, variant는 기본적으로 공개
- 구조체는 pub을 명시하지 않으면 비공개
<use>
: 함수 호출을 할 때마다 경로를 작성하지 않고, use를 사용해 단축 경로를 만듭니다. 단, use가 사용된 특정 스코프 내에서만 단축 경로가 만들어집니다. 지켜지지 않을 경우 다음과 같은 에러가 나옵니다 : error[E0433]: failed to resolve: use of undeclared crate or module `hosting`
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
...
use crate::front_of_house::hosting; // hosting의 단축 경로
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
mod customer {
pub fn eat_at_restaurant() {
hosting::add_to_waitlist(); // use 구문과 다른 스코프가 되어 컴파일되지 않음
}
}
- 이름이 같은 두 타입을 동일한 스코프에 가져오기 위해서는 반드시 다음과 같이 부모 모듈을 명시해주어야 합니다.
use std::fmt;
use std::io;
fn function1() -> fmt::Result { }
fn function2() -> io::Result<()> { }
as 키워드로 다음과 같이 하나의 타입 이름을 바꿔줄 수도 있습니다.
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --생략--
}
fn function2() -> IoResult<()> {
// --생략--
}
- 외부 패키지
use rand::Rng;
fn main() {
let num = rand::thread_rng().gen_range(0..10); //0~9 사이의 숫자를 랜덤으로 픽
}
- 중첩 경로
use std::cmp::Ordering;
use std::io;
// 위와 같은 코드를 아래와 같은 중첩 경로로 적을 수 있습니다.
use std::{cmp::Ordering, io};
- 글롭 연산자 : 경로에 글롭(glob. *)을 붙이면 경로 안에 정의된 모든 pub 아이템을 가져올 수 있습니다.
use std::collections::*;
'[Rust]' 카테고리의 다른 글
[Rust] match 연산자 (0) | 2023.08.15 |
---|---|
[Rust] 컬렉션(Collection) (0) | 2023.08.14 |
[Rust] 열거형(enum) (0) | 2023.08.01 |
[Rust] 구조체 - 메서드 (0) | 2023.07.30 |
[Rust] 데이터 구조체 (0) | 2023.07.29 |