[Rust] study Project Organization and Structure

Rust 프로젝트 구성과 구조

Posted by lim.Chuck on August 23, 2024

[Rust]

  1. [Rust] Rust 설치
  2. [Rust] Hello Cargo
  3. [Rust] VSCode 설정
  4. [Rust] Rust 공부 시작
  5. [Rust] Rust 기초
  6. [Rust] Rust 제어문
  7. [Rust] Rust 자료형
  8. [Rust] Rust 제네릭
  9. [Rust] Rust 소유권, 대여, 데이터
  10. [Rust] study Text
  11. [Rust] Rust 객체지향 프로그래밍
  12. [Rust] Rust 스마트 포인터
  13. [Rust] Rust 프로젝트 구성 및 구조

참고문서
《 Tour of Rust 》
《 Rust_Book 》
《 프로그래밍 언어 러스트를 배웁시다! 》
《 rust module 》

프로젝트 구성과 구조

지금까지의 모든 예제 코드는 단일 파일이었습니다. 어떻게 하면 우리의 코드를 더 잘 구성하고 다른 사람과 공유할 수 있을지 얘기해 봅시다!

1. 모듈

모든 Rust 프로그램이나 라이브러리(library)는 크레이트(crate)입니다.

모든 crate는 모듈(module)의 계층구조로 이루어져 있습니다.

모든 crate에는 최상위(root) module이 있습니다.

module에는 전역변수, 함수, struct, trait, 또는 다른 module까지도 포함될 수 있습니다!

Rust에서는 파일과 module 트리 계층구조 간의 1:1 대응은 없습니다. module의 트리 구조는 코드로 직접 작성해야 합니다.

2. 프로그램 작성하기

프로그램은 main.rs라 불리는 파일에 root module을 갖고 있습니다.

3. 라이브러리 작성하기

library는 lib.rs라 불리는 파일에 root module을 갖고 있습니다.

4. 다른 모듈과 크레이트 참조하기

module 내의 항목은 전체 module 경로인 std::f64::consts::PI를 이용해 참조할 수 있습니다.

더 간단한 방법은 use 키워드를 사용하는 것입니다. 이를 이용하면 module에서 쓰고자 하는 특정 항목을 전체 경로를 쓰지 않고도 코드 어디에서든 사용할 수 있습니다. 예를 들어, use std::f64::consts::PI를 쓰면 main 함수에서 PI만으로 사용할 수 있습니다.

std는 유용한 데이터 구조 및 OS와 상호작용할 수 있는 함수로 가득한 표준 라이브러리 (standard library)의 crate입니다.

커뮤니티에서 작성한 crate들의 검색 가능 목록을 https://crates.io에서 확인하실 수 있습니다.

1
2
3
4
5
6
use std::f64::consts::PI;

fn main() {
    println!("놀이터에 오신 것을 환영합니다!");
    println!("{} 한 조각 먹고 싶군요!", PI);
}
$ 놀이터에 오신 것을 환영합니다!
$ 3.141592653589793 한 조각 먹고 싶군요!

5. 여러 개의 항목을 참조하기

복수의 항목을 하나의 module 경로로 참조하고 싶다면 이렇게 하면 됩니다:

use std::f64::consts::{PI,TAU} Ferris는 TAU를 먹지 않습니다. PI만 먹어요.

6. 모듈 작성하기

코드를 생각할 때 보통은 디렉토리로 구성된 파일구조를 떠올립니다. Rust는 여러분의 파일 구조에 가깝게 module을 만들 수 있게 해줍니다.

Rust에서 module을 선언하는 데에는 두 가지 방법이 있습니다. 예를 들어 foo module은 다음과 같이 나타낼 수 있습니다:

  • foo.rs라는 이름의 파일
  • foo라는 이름의 디렉토리에 들어있는 파일 mod.rs

7. 모듈 계층구조

한 module은 다른 module에 의존할 수 있습니다. module과 하위모듈(sub-module) 사이에 관계를 지어주려면, 부모 module에 다음과 같은 코드를 작성합니다:

mod foo; 위 선언은 foo.rs 파일이나 foo/mod.rs 파일을 찾아 이 scope 내의 foo module안에 그 내용물을 삽입합니다.

8. 인라인 모듈

sub-module은 module의 코드 내에 직접 치환(inline)될 수 있습니다.

inline module의 가장 흔한 용도는 단위 테스트를 만들 때입니다. Rust가 테스트에 쓰일 때에만 존재하는 inline module을 만들어 봅시다!

1
2
3
4
5
6
7
8
9
10
// 이 macro는 Rust가 테스트 모드가 아닐 경우
// 이 inline module을 제거합니다.
#[cfg(test)]
mod tests {
    // 부모 module에 즉시 접근이 가능하지 않다는 데에 주의하세요.
    // 반드시 명시적으로 써줘야 합니다.
    use super::*;

    ... tests go here ...
}

9. 내부 모듈 참조하기

Rust에서는 use 경로에 사용할 수 있는 몇 가지 키워드를 통해 원하는 module을 빠르게 가져다 쓸 수 있습니다:

  • crate - root module
  • super - 현재 module의 부모 module
  • self - 현재 module

10. 내보내기

기본적으로 module의 구성원들은 외부에서 접근이 불가능합니다 (그 자식 module에게까지도!). pub 키워드를 사용하면 module의 구성원들을 접근 가능하게 할 수 있습니다.

기본적으로 crate의 구성원들도 외부에서 접근이 불가능합니다. crate의 root module (lib.rs 또는 main.rs)에 pub을 표시하면 구성원들을 접근 가능하게 할 수 있습니다.

11. 구조체 가시성

함수와 마찬가지로, structure도 module 외부로 무엇을 노출할지를 pub을 사용해 선언할 수 있습니다.

1
2
3
4
5
6
7
8
9
// SeaCreature struct는 우리 module 외부에서도 사용 가능합니다
pub struct SeaCreature {
    pub animal_type: String,
    pub name: String,
    pub arms: i32,
    pub legs: i32,
    // 우리의 무기는 비밀로 남겨둡시다
    weapon: String,
}

12. 전주곡 (Prelude)

use로 가져오지도 않았는데 어떻게 어디서나 VecBox를 쓸 수 있는지 궁금하실지도 모르겠습니다. 이는 standard library의 prelude module 덕분입니다.

Rust의 standard library에서는 std::prelude::*로 내보내기 된 모든 것들이 어디에서든 자동으로 사용 가능하다는 점을 알아두십시오. VecBox가 바로 이런 경우이며, 다른 것들(Option, Copy, 기타 등등)도 마찬가지입니다.

13. 여러분만의 Prelude

standard library의 prelude로 인해, 흔히들 library마다 고유의 prelude module을 만들어 library 사용을 위해 필요한 가장 흔한 데이터 구조들을 모두 가져오는 시작점으로 쓰곤 합니다 (예: use my_library::prelude::*). standard library와 달리 프로그램이나 library에서 자동으로 쓸 수 있는 것은 아니지만, library 사용자들이 어디서부터 시작할지 도움을 줄 좋은 습관입니다.

Ferris가 말하길, “좋은 rustacean이 되어, 좋은 prelude로 게 친구를 도와주세요!”

마무리

pub을 사용해서 모듈 불러서 쓰셈

이제 여러분의 소매 속에는 Rust 프로그램과 library를 만드는 데에 쓸 몇 가지 재주가 생겼습니다. 이걸 모두 기억하려고 하지 마세요. 여러분의 library가 커져감에 따라, 또 다른 사람들이 사용함에 따라, 각 단계에서 뭐가 가장 좋은 방법인지 알게 될 것입니다.

자료: Guidelines For Writing Rust APIs