Rust는 어떤 세부 정보가 노출되는지, 비공개인지, 프로그램의 각 범위에 어떤 이름이 있는지 같은 코드 구성을 관리할 수 있는 여러 기능들이 있다.
module system이라고 하는 이러한 기능에는 다음을 포함한다.
- Packages: Crate를 만들고, 테스트하고, 공유하는 Cargo feature
- Crates: 라이브러리를 저장하는 모듈 저장소
- Moduels: paths를 관리하고, 범위를 나누고, 보호할 수 있게 함
- Paths: 구조체, 함수, 모듈같은 아이템들을 naming 하는 방법
패키지, 크레이트
우선 cargo new 명령어로 패키지를 만든다.
패키지는 어떠한 기능을 제공하는 하나이상의 크레이트 집합이다.
Cargo가 생성한 Cargo.toml파일은 new 패키지의 의존성과 메타데이터를 관리하는 manifest 파일이다.
Cargo.toml파일 안에 main.rs에 대한 내용이 없지만, 아래와 같은 규칙을 자동으로 따르기 때문에 main.rs를 실행한다.
- src/main.rs는 같은 패키지와 같은 이름을 가진 바이너리 크레이트의 크레이트 루트이다.
바이너리 크레이트의 crate root는 main.rs이고, 라이브러리 크레이트의 crate root는 lib.rs이다.
따라서 Cargo는 lib.rs가 있다면 자동으로 lib.rs를 실행시킨다.
패키지에는 최대 하나의 라이브러리 크레이트만을 생성할 수 있다.
Cargo는 라이브러리/바이너리를 빌드하기 위해 crate root 파일들을 rustc에 넘긴다.
crate root는 컴파일러에게 패키지를 어디에서 시작해야하는지 알려주는 역할을 한다.
이제는 cargo 명령어를 사용하여 컴파일/빌드 하지만 처음에 Hello, world!에서는 rustc를 사용했던걸 기억해보자.
패키지의 src폴더에 main.rs가 있으면 바이너리 크레이트가 생성되고, lib.rs가 있으면 라이브러리 크레이트가 생성된다.
둘 다 생성될 수 있으며, 생성된 크레이트는 패키지 이름과 같다.
패키지에서는 main.rs외에도 bin 폴더를 만들어 여러 크레이트를 사용할 수 있다.
각 파일은 별도의 바이너리 크레이트가 된다.
크레이트는 범위안의 관련 기능을 함께 묶어 여러 프로젝트들 간에 기능이 쉽게 공유될 수 있다.
예를 들어 Hello, world! 에서 쓰였던 rand 크레이트의 기능은 new 패키지 안의 여러 크레이트에서 쓰일 수 있다.
다른 크레이트에서 제공하는 데이터를 자신의 크레이트 안에 선언해서 사용는 것도 가능하다.
예를 들어 rand 크레이트 안의 rng라는 특성을 제공하는데, 자신의 크레이트 안에 rng라는 struct를 사용하는 것이 가능하다.
컴파일러는 이 둘을 헷갈려 하지 않는데, 이는 namespace 때문이다.
자신의 크레이트 안에서는 struct rng라고 선언하여 사용하고, rand 크레이트의 rng를 사용할 때는 rand::rng라고 namespace를 붙여 사용해야한다.
모듈과 경로
앞서 나올 키워드들을 간략히 소개하자면 use, pub, as와 같은 것들이 있다.
use 키워드를 이용하여 item을 사용하려는 범위로 가져오고,
pub 키워드를 이용하여 item을 public으로 지정할 수 있고,
as 키워드로 별칭을 지정할 수도 있다.
여기서 item은 함수, 메서드, 구조체, 열거형, 모듈, 상수를 의미하고 앞으로 다루어 볼 내용은 모듈에 초점이 맞춰져 있다.
모듈은 크레이트 내의 코드를 가독성과 재사용이 용이하게 그룹화하고, privacy를 제어한다. 외부에서 사용할 수 있는 경우 public, 내부에서만 사용하는 경우 private를 사용한다.
예로, 레스토랑 운영을 생각해 보자. 레스토랑 내부의 일은 쉐프와 조리에 관련된 일, 외부의 일은 손님에 관한 일이 될 것이다. cargo new --lib restaurant; 코드로 라이브러리 폴더를 생성할 수 있다. 이때 mod 키워드를 이용하여 lib.rs에 새로운 라이브러리 크레이트를 연결해 주어야 한다.
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() {}
}
}
모듈을 정의하려면 mod 키워드를 사용하여 모듈의 이름을 정의한다.(front_of_house)
모듈은 다른 item을 포괄할 수 있다.(구조체, 열거형, 상수, 특성 등등...) 때문에 관련된 기능들을 모아 그룹화 시킬 수 있다. 이렇게 잘 정리된 모듈은 프로그래머가 쉽게 기능을 이해하고 프로그램을 더 잘 작성할 수 있게 도와준다.
위 코드의 모듈 트리는 이런 구조이다.
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment
모듈 트리에서 item을 찾기 위해, 파일 시스템과 동일한 방식의 path를 사용한다.
path는 items(구조체, 함수, 모듈)에 naming하는 방법에 관한 기능이다. path는 다음과 같은 두가지 방식이 있다.
- 절대 경로 : 크레이드 이름이나 'crate'라는 문자 자체를 찾아 크레이트 root에서 시작
- 상대 경로 : 현재 모듈이나 모듈의 self, super, identifier에서 시작
두 경로 모두 더블 콜론(::)에 의해 구분된 하나 이상의 식별자(identifier)가 온다.
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
위는 eat_at_restaurant()에서 add_to_waitlist()를 호출하는 두 가지 방법에 대해 보여준다.
컴파일 결과에 대해 이야기해 보자.
hosting은 private module이기 때문에 에러가 표시된다.
러스트는 호출된 함수가 경로에 접근 권한이 없다고 판단하면 코드를 실행시키지 않는다.
모든 item(함수, 메서드, 구조체, 열거형, 모듈, 상수)은 디폴트로 private이다.
부모 모듈은 자식 모듈의 private item을 사용할 수 없지만, 그 반대는 가능하다.
자식 모듈은 래핑하고 그들의 세부 구현을 숨기지만, 그들이 정의한 컨텍스트를 볼 수 있기 때문이다.
만약 자식 모듈의 코드를 외부의 부모 모듈에게 보이고 싶다면 pub 키워드를 이용해 item을 public으로 만들 수 있다.
위의 예시에서 hosting을 pub로 바꾸어 실행시켜 보자.
hosting은 pub을 붙였기 때문에 public이 되었지만, hosting이 호출하는 add_to_waitlist함수는 여전히 private이기 때문에 hosting은 문맥상 여전히 private이다.
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
이제 컴파일 가능한 완전한 코드가 작성되었다!
절대 경로에서는 자신의 크레이트 모듈 트리의 루트인 crate로 시작하고, front_of_house로 넘어간다. 이때 front_of_house는 public이 아니지만, eat_at_restaurant 함수가 같은 모듈 안에 정의되어 있으므로 front_of_house를 참조할 수 있다. 그리고 public인 hosting과 add_to_waitlist를 지나 함수를 호출할 수 있다.
상대 경로에서는 front_of_house로 시작하는 첫 번째 과정을 제외하면 절대 경로의 과정과 같다.
'러스트' 카테고리의 다른 글
공통 컬렉션(Common Collections) - 백터 (0) | 2022.03.14 |
---|---|
패키지, 크레이트, 모듈(2) (0) | 2022.03.12 |
열거형과 Match (0) | 2022.03.11 |
구조체 (0) | 2022.03.10 |
소유권(2) (0) | 2022.03.08 |