ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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
Designed by Tistory.