크레이트 : 실행(bin) 또는 라이브러리(lib) 같은 동작 가능한 코드가 들어있는 바이너리 파일
모듈 : 크레이트 구조화 할 수 있는 하위 구성 단위
최상위에 communicator 모듈이 있고 하위에 client, network 모듈이 있다.
my_mod
├── elf_reader
└── common_reader
└── file_reader
이를 구성하기 위해서는 다음과 같이 파일 레이아웃을 구성한다.
my_mod
├── src
│ ├── elf_reader.rs
│ ├── lib.rs
│ └── common_reader
│ ├── mod.rs
│ └── file_reader.rs
Rust는 기본적으로 src/lib.rs를 알아서 찾을 수 있다.
만약 다른 mod들이 있다면 src/lib.rs에 기록을 해야 한다.
src/lib.rs는 다른 src/{somthing}.rs 파일들과 다르다
src/lib.rs
/*
아래 코드는 다음과 같다
mod common_reader {
content of common_reader
}
mod elf_reader {
content of elf_reader
}
*/
mod common_reader;
mod elf_reader;
src/elf_reader.rs
fn add_two(a: i32) -> i32 {
// common_reader::internal_adder(a, 2)
32
}
lib.rs에서 common_reader, elf_reader라는 모듈이 있으며 그 정의는 외부 파일에 기록되어 있다.
모듈은 외부에 다음과 같은 형태의 파일로 존재할 수 있다.
ex) common_reader
이 예에서는 src/common_reader/mod.rs 와 같이 존재하는데 이유는 common_reader 모듈 자체가 file_reader라는 하위 모듈을 가지고 있기 때문이다
src/common_reader/mod.rs
//하위 모듈 있다. 같은 규칙을 적용해서 외부에 file_reader 모듈 정의가 있다.
mod file_reader;
fn internal_adder(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn internal() {
assert_eq!(4, internal_adder(2, 2));
}
}
src/common_reader/file_reader.rs
fn read() {
}
모듈 구조화 규칙은 재귀적으로 적용된다.
굳이 여러 파일과 디렉터리를 사용하여 모듈화 하지 않고 lib.rs에 모두 적을 수 있다.
mod client {
fn connect() {
}
}
mod network {
fn connect() {
}
mod server {
fn connect() {
}
}
}
extern crate elf_reader;
fn main() {
println!("Hello, world! {}", elf_reader::elf_reader::add_two(10));
}
elf_reader 크레이트를 추가해서 사용하려면 cargo.toml 파일에 의존성을 명시 해주어야 한다.
[package]
name = "file-viewer"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
elf_reader = { path = "elf_reader", version = "0.1.0" }
[dependencies]
부분에 elf_reader 의존성을 추가하였다.
저 버전은 = 연산뿐만 아니라 >, <=, ... 등 다른 비교 연산도 가능
심플하다. pub 를 통해 공개한다.
단 같은 모듈 파일에 있을 경우 pub는 필요 없다.
mod outermost { // 비공개지만 같은 루트 모듈에 있어 OK
pub fn middle_function() {} // OK
fn middle_secret_function() {} // FAIL, pub 필요
mod inside { // FAIL, pub 필요
pub fn inner_function() {}
fn secret_function() {} // FAIL, pub 필요
}
}
fn main() {
outermost::middle_function();
outermost::middle_secret_function();
outermost::inside::inner_function();
outermost::inside::secret_function();
}
private 가시성 모듈은 접근이 불가능 하다
mod outermost {
pub mod inside {
pub fn inner_function() {
}
fn secret_function() {} // FAIL, pub 필요
}
}
fn main() {
outermost::inside::inner_function();
outermost::inside::secret_function();
}
public 메서드에서 private 메서드를 대리 호출하면 호출 가능하다.
inner_function은 secret_function과 함께 같은 루드 모듈인 outermost에 있기 때문이다.
mod outermost {
pub mod inside {
pub fn inner_function() {
secret_function();
}
fn secret_function() {} // OK, inner_function으로 호출 가능
}
}
fn main() {
outermost::inside::inner_function();
}
호출시 경로는 기본적으로 현재 모듈을 기준으로 상대 경로로 해석한다.
other::secret_function 호출시 현재 모듈은 inside이다.
mod outermost {
mod other {
pub fn secret_function() {
println!("call me");
}
}
pub mod inside {
pub fn inner_function() {
other::secret_function(); // FAIL
}
}
}
fn main() {
outermost::inside::inner_function();
}
단 하나 예외는 use 구분인데 이는 기본적으로 크레이트 루트에 대한 상대적인 경로로 인식한다.
이 문제를 해결하기 위해서는 상위 모듈로 접근할 수 있는 방법이 필요하다
mod outermost {
mod other {
pub fn secret_function() {
println!("call me");
}
}
pub mod inside {
pub fn inner_function() {
crate::outermost::other::secret_function();
super::other::secret_function();
}
pub mod deep_inside {
pub fn deep_inner_function() {
crate::outermost::other::secret_function();
super::super::other::secret_function();
}
}
}
}
fn main() {
outermost::inside::inner_function();
outermost::inside::deep_inside::deep_inner_function();
}