오늘은 Rust의 use, as, mod에 대해 알아보고자 합니다.
use 키워드로 경로를 스코프 안으로 가져오기
함수 호출을 위해서 경로를 작성하는 것은 불편하고 반복적인 느낌을 줄 수 있습니다.
use 키워드를 한번 사용하여 어떤 경로의 단축여로(shortcut)을 만들 수 있고, 그러면 스코프 안쪽 어디서라도 짧은 이름을 사용할 수 있습니다.
다음 예제는 crate::front_of_house::hosting 모듈을 eat_at_restaurant 함수가 존재하는 스코프로 가져와, eat_at_restaurant 함수 내에서 add_to_waitlist 함수를 hosting:;add_to_waitlist경로만으로 호출하는 예제입니다.
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
스코프에 use 키워드와 경로를 작성하는 건 파일 시스템에서 심볼릭 링크(symbolic link)를 생성하는 것과 유사합니다.
크레이트 루트에 use crate::front_of_house::hosting을 작성하면 해당 스코프에서 hosting 모듈을 크레이트 루트에 정의한 것처럼 사용할 수 있습니다.
use가 사용된 특정한 스코프에서만 단축 경로가 만들어집니다.
다음 예제에서는 eat_at_restaurant 함수를 새로운 자식 모듈 customer로 옮겼는데, 이러면 use구문과 다른 스코프가 되므로, 이 함수는 컴파일 되지 않습니다.
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();
}
}
컴파일러는 customer 모듈 내에 더 이상 단축경로가 적용되지 않음을 알려줍니다.
warning: unused import: `crate::front_of_house::hosting`
--> src/lib.rs:7:5
|
7 | use crate::front_of_house::hosting;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error[E0433]: failed to resolve: use of undeclared crate or module `hosting`
--> src/lib.rs:11:9
|
11 | hosting::add_to_waitlist();
| ^^^^^^^ use of undeclared crate or module `hosting`
For more information about this error, try `rustc --explain E0433`.
warning: `restaurant` (lib) generated 1 warning
error: could not compile `restaurant` due to previous error; 1 warning emitted
이 문제를 해결하려면 use로 customer 모듈 안쪽으로 옮기거나, customer모듈 내에서 super::hosting을 써서 부모 모듈로의 단축경로를 참조하면 됩니다.
보편적인 use 경로 작성법
왜 add_to_waitlist 함수를 사용하는데 경로를 전부 작성하지 않고 hosting까지만 작성하는 걸까요?
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting::add_to_waitlist;
pub fn eat_at_restaurant() {
add_to_waitlist();
}
물론 다음과 같이 작성해도 동일하게 작동합니다.
함수의 부모 모듈을 use키워드로 가져오면 함수를 호출할 때 부모 모듈을 특정해야 합니다.
함수 호출 시 부모 모듈을 특정하면 전체 경로를 반복하는 것을 최소화하면서도 함수가 로컬에 정의되어 있지 않음을 명백히 보여주게 됩니다.
한편, use 키워드로 구조체나 열거형 등의 타 아이템을 가져올 시에는 전체 경로를 작성하는 것이 보편적입니다.
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}
동일한 이름의 아이템을 여럿 가져오는 경우에는 rust가 허용하지 않아 이 방식을 사용하지 않습니다.
use std::fmt;
use std::io;
fn function1() -> fmt::Result {
// --생략--
}
fn function2() -> io::Result<()> {
// --생략--
}
동일한 스코프 내에 두 개의 Result 타입이 존재하므로, rust는 우리가 어떤 Result타입을 사용했는지 알 수 없습니다.
as 키워드로 새로운 이름 제공하기
use 키워드로 동일한 이름의 타입을 스코프로 여러 개 가져올 경우의 또 다른 방법으로 경로 뒤에 as 키워드를 작성하고, 새로운 이름이나 타입의 별칭을 작성하면 됩니다.
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --생략--
}
fn function2() -> IoResult<()> {
// --생략--
}
pub use로 다시 내보내기
use 키워드로 이름을 가져올 경우, 해당 이름은 새 위치의 스코프에서 비공개가 됩니다.
pub와 use를 결합하면 우리 코드를 호출하는 코드가 해당 스코프에 정의된 것처럼 해당 이름을 참조할 수 있습니다.
이 기법은 아이템을 스코프로 가져오는 동시에 다른 곳에서 아이템을 가져갈 수 있도록 만들기 때문에, 다시 내보내기(re-exporting)이라고 합니다.
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
pub use가 root 모듈로부터 hosting을 가져와 다시 내보냈으니, 이제 외부 코드는 restaurant::hosting:;add_to_waitlist() 경로를 대신 사용할 수 있습니다.
pub use를 사용하면 코드를 작성할 때의 구조와, 노출할 때의 구조를 다르게 만들 수 있습니다.
라이브러리를 제적하는 프로그래머와, 라이브러리를 사용하는 프로그래머 모두를 위한 라이브러리를 구성하는 데 큰 도움이 되죠.
중첩 경로를 사용하여 대량의 use 나열을 정리하기
use std::cmp::Ordering;
use std::io;
다음과 같이 선언한 use문을 간략화할 수 있습니다.
use std::{cmp::Ordering, io};
규모가 큰 프로그램이라면, 동일한 크레이트나 모듈에서 여러 아이템을 가져올 때 중첩 경로를 사용함으로써 많은 use 구문을 줄일 수 있습니다.
만일 std::io를 스코프로 하나 가져오고, 다른 하나는 std::io::Write를 가져오는 경우에는 어떻게 해야할까요?
use std::io;
use std::io::Write;
std::io 는 첫 번째 경로 그자체이기 때문에, 중첩 경로에 self를 작성하면 두 경로를 하나의 use 구문으로 합칠 수 있습니다.
use std::io::{self, Write};
글롭 연산자
경로에 글롭(glob) 연산자 *을 붙이면 경로 안에 정의된 모든 공개 아이템을 가져올 수 있습니다.
use std::collections::*;
별개의 파일로 모듈 분리하기
src/front_of_house.rs 파일이 다음과 같이 존재합니다.
pub mod hosting {
pub fn add_to_waitlist() {}
}
해당 파일을 src/lib.rs에서 가져옵니다.
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
모듈 트리에서 mod 선언을 사용하여 파일을 로드하는 것은 한번만 하면 됩니다.
그 파일이 프로젝트의 일부란 것을 컴파일러가 파악하면, 프로젝트의 다른 파일들은 선언된 위치의 경로를 사용하여 로드된 파일의 코드를 참조해야 합니다.
즉, mod는 다른 프로그래밍 언어에서 볼 수 있는 포함하기(include)연산이 아닙니다.
정리
- use를 활용하여 필요한 함수의 경로를 호출해서 사용할 수 있습니다.
- pub use를 활용해서 가져온 함수의 경로를 현재 파일로 변경하여 다시 내보낼 수 있습니다.
- 만일, use로 가져온 함수명이 같은 경우 as로 새로운 이름을 제공하여 활용할 수 있습니다.
'Rust' 카테고리의 다른 글
Rust 설치부터 실행까지 (crate, 절대 경로, 상대 경로, super, use, pub) - 15 (0) | 2025.01.13 |
---|---|
Rust 설치부터 실행까지 (match, if let) - 14 (0) | 2025.01.12 |
Rust 설치부터 실행까지 (열거형, Option) - 13 (0) | 2025.01.12 |
Rust 설치부터 실행까지 (메서드) - 12 (0) | 2025.01.09 |
Rust 설치부터 실행까지 (구조체, 디버깅) - 11 (0) | 2025.01.07 |
댓글