-
[Rust] 7. 모듈시스템에 대하여rust 2023. 2. 5. 14:28반응형
대부분의 예시는 하나의 모듈과 하나의 파일로 이루어져 있지만 프로젝트가 커질수록 여러개의 모듈과 여러개의 파일로 코드를 작성해야 할것이다. 하나의 패키지는 여러개의 binary crates 혹은 하나의 library crate 를 생성할수 있다. 이러한 rust에서 파일을 관리하는데 필요한 개념들을 공부해보는 목적으로 작성된 글이다.
- Packages: A Cargo feature that lets you build, test, and share crates
- Crates: A tree of modules that produces a library or executable
- Modules and use: Let you control the organization, scope, and privacy of paths
- Paths: A way of naming an item, such as a struct, function, or module
rust 모듈시스템 4가지의 특징과 역할을 살펴보자
crate
- crate는 rust compiler 가 고려하는 가장작은 단위이다
- crate 는 binary crate 와 library crate 로 나눌수 있다.
- binary crate 은 실행가능한 파일이며 반드시 실행에 필요한 main 함수를 가지고 있다.
- library crate 은 실행이 불가능한 파일이며 main 함수를 보유하고 있지 않다 대신에 여러프로젝트 에서 사용가능한 함수를 정의해놓을수 있다.
- module tree 는 src/lib.rs 에 정의하면 binary crate 에서 패키지 이름의 경로를 통해 외부 라이브러리를 사용하듯이 사용할수 있게 되면 이는 좋은 api 를 설계하는 방법이 된다.
package
- 하나 이상의 crates의 모음을 package 라고 하며 package 는 crates 들을 설명하는 cargo.toml 파일을 보유하고 있다.
- cargo new 를 실행하면 src/main.rs 파일을 확인할수 있으며 이파일은 binary crate 의 root file convention naming 이다.
- cargo new --lib 을 실행하면 src/lib.rs 는 library crate 의 root file 이다.
- package 는 src/bin directory 를 이용해 여러개의 binary crate를 가지고 있을수 있다.
path
- use keyword 를 사용해 path 를 스코프내로 불러와 사용할수있다.
- pub keyword 를 사용해 items 를 public 하게 사용할수있다.
- as keyword를 사용해 외부 패키지의 이름을 바꿔 사용할수있다.
- path 에는 절대경로 상대경로로 나눌수 있으며 절대경로는 crate 부터 시작한다
- 상대경로는 현재모듈 부터 시작하며 self, super 키워드를 사용할수 있다.
- 일반적으로 절대경로를 선호하지만 프로젝트에 따라 코드와 별도로 이동할지 함께이동할지를 고려해서 사용하면된다.
- 경로의 접근은 :: double colons 를 사용한다.
mod front_of_house { mod hosting { // error[E0603]: module `hosting` is private fn add_to_waitlist() {} // error[E0603]: function `add_to_waitlist` is private } } pub fn eat_at_restaurant() { // Absolute path crate::front_of_house::hosting::add_to_waitlist(); // Relative path front_of_house::hosting::add_to_waitlist(); }
- 위와같이 hosting 에 접근 하는 것은 경로에는 문제가 없으나 rust 에서 모든아이템 (functions, methods, structs, enums, modules, and constants)은 기본적으로 상위모듈에 대해 private 하다. 따라서 아이템을 비공개로 관리하고 싶다면 모듈에 넣어서 관리할수도 있다
- 부모는 자식모듈의 아이템을 사용할수 없지만 자식은 부모 모듈의 아이템을 사용할수 있다.
- pub 키워드를 사용하면 부모가 자식모듈의 코드에 접근할수 있도록한다.
- pub 키워드를 hosting 에만 붙여준다면 hosting mod 는 접근할수 있지만 모듈안의 아에템은 여전히 private 하기 대문에 함수에도 pub 키워드를 사용해줘야한다.
- 상대경로에서 super 키워드를 통해 한단계 부모모듈부터 경로를 시작할수있다.
fn deliver_order() {} mod back_of_house { fn fix_incorrect_order() { cook_order(); super::deliver_order(); } fn cook_order() {} }
module rules
-Start from the crate root: 일반적으로 라이브러리 crate는 src/lib.rs, 바이너리 crate는 src/main.rs 에서 컴파일할 코드를 찾습니다.
- Declaring modules: mod garden; 으로 대체할수 있으며 파일위치는 src/garden.rs || src/garden/mod.rs
- Paths to code in modules: module이 public이고 crate의 일부라마면 crate의 다른 파일에서 모듈의 코드를 사용할수있다.
- Private vs public: module 은 기본적으로 private 하며 pub 키워드를 통해 module 을 public 하게 사용할수 있다.
- The use keyword: use 키워드를 통해 path 의 길이를 줄여서 scope 내에서 사용 가능하다.
ex
use crate::garden::vegetables::Asparagus; pub mod garden; fn main() { let plant = Asparagus {}; println!("I'm growing {:?}!", plant); }
mod front_of_house { mod hosting { fn add_to_waitlist() {} fn seat_at_table() {} } mod serving { fn take_order() {} fn serve_order() {} fn take_payment() {} } } crate └── front_of_house ├── hosting │ ├── add_to_waitlist │ └── seat_at_table └── serving ├── take_order ├── serve_order └── take_payment
public
- pub 키워드는 struct 와 enum 에도 사용할수 있는데 여기에는 몇가지 추가적으로 알아야할 사항들이 있다.
- 구조체의 경우 pub 으로 선언하다라도 구조체의 filed는 여전히 private 하다. 우리는 역할에 따라 일부필드만 public 하게 사용할수 있다.
mod back_of_house { pub struct Breakfast { pub toast: String, seasonal_fruit: String, } impl Breakfast { pub fn summer(toast: &str) -> Breakfast { Breakfast { toast: String::from(toast), seasonal_fruit: String::from("peaches"), } } } } pub fn eat_at_restaurant() { // Order a breakfast in the summer with Rye toast let mut meal = back_of_house::Breakfast::summer("Rye"); // Change our mind about what bread we'd like meal.toast = String::from("Wheat"); println!("I'd like {} toast please", meal.toast); // The next line won't compile if we uncomment it; we're not allowed // to see or modify the seasonal fruit that comes with the meal // meal.seasonal_fruit = String::from("blueberries"); }
- 이와 대조적으로 enum pub 키워드를 같이 사용한다면 enum의 변수들 역시 public 하게 접근할수 있게된다.
- enum 은 변수를 public 하게 관리하는 경우가 많지 않아 일일이 지정해줄 필요성이 없지만 struct는 종종 public을 유용하게 사용하기 때문에 차이가 있다.
mod back_of_house { pub enum Appetizer { Soup, Salad, } } pub fn eat_at_restaurant() { let order1 = back_of_house::Appetizer::Soup; let order2 = back_of_house::Appetizer::Salad; }
use
- 외부경로의 함수를 실행할때마다 경로를 반복해서 사용하는 것은 불편한데 이러한 부분을 도와주는 키워드가 use 이다.
- use 키워드는 파일시스템의 심볼릭링크와 비슷한데 use 키워드를 이용해 crate root 에 경로를 설정해준다면 해당 scope 내에서 경로를 바로 사용할수 있다.
mod front_of_house { pub mod hosting { pub fn add_to_waitlist() {} } } use crate::front_of_house::hosting; mod customer { pub fn eat_at_restaurant() { hosting::add_to_waitlist(); //error[E0433]: failed to resolve: use of undeclared crate or module `hosting` } }
- 위의 예시는 use 키워드를 사용한 scope과 사용부분의 scope이 다르기 때문에 에러가 난다.
- 일반적으로 함수를 가져올때는 함수의 container 모듈까지만 가져와서 모듈을 통해 함수를 호출한다 왜냐하면 함수의 선언부를 정확히 명시하기 위함이다 그러나 struct 나 enum 등 다른 아이템은 특정 아이템까지 use 키워드를 사용해 path를 불러오는 것이 일반적인 사용이다.
'rust' 카테고리의 다른 글
[Rust] collection(1)-vector (0) 2023.02.06 [Rust] 6. enum과 match에 대하여 (0) 2023.02.02 [Defi] 디파이 시작해보기(1) (0) 2023.02.01 [Rust] 5. struct에 대하여 (0) 2023.01.31 [Rust] 4.ownership(3). slice (0) 2023.01.28