`use` 키워드로 경로를 스코프 안으로 가져오기
use·as·pub use와 중첩·글롭 경로를 사용해 모듈 및 외부 패키지의 이름을 현재 스코프에 명확하게 가져옵니다.
함수를 부를 때마다 경로를 모두 적는 것은 번거롭습니다. 모듈 경로와 아이템 참조에서는 절대 경로든 상대 경로든 add_to_waitlist를 부를 때마다 front_of_house와 hosting을 적어야 했습니다. use 키워드를 쓰면 경로의 줄임 이름을 한 번 만들어 두고, 그 스코프 안에서는 짧은 이름을 쓸 수 있습니다. 이 글에서는 use의 쓰임과 관례, as로 이름을 바꾸는 방법, pub use로 다시 내보내는 방법, 외부 패키지를 쓰는 방법, 그리고 여러 use를 줄이는 중첩 경로와 글롭 연산자를 살펴봅니다.
use로 이름 가져오기
다음 코드는 crate::front_of_house::hosting 모듈을 eat_at_restaurant가 있는 스코프로 가져와, eat_at_restaurant 안에서 hosting::add_to_waitlist만으로 함수를 부릅니다. use 줄은 함수 바깥의 크레이트 루트에 있고, 함수 안의 호출은 경로의 마지막 모듈 이름인 hosting부터 적는다는 점을 보세요.
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는 대상을 옮기거나 복사하지 않고 이름만 묶으며, use의 경로도 다른 경로와 똑같이 공개 여부를 검사받으므로 비공개 아이템을 쓸 수 있게 해 주지는 않습니다.
use가 만든 줄임 이름은 그 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();
}
}error[E0433]: cannot find module or crate `hosting` in this scope
--> src/lib.rs:11:9
|
11 | hosting::add_to_waitlist();
| ^^^^^^^ use of unresolved module or unlinked crate `hosting`컴파일러는 customer 모듈 안에서는 hosting이라는 이름을 찾을 수 없다는 E0433 오류와 함께, 7번째 줄의 use가 쓰이지 않는다는 경고도 냅니다. 고치려면 use를 customer 모듈 안으로 옮기거나, customer 안에서 super::hosting으로 부모 모듈의 줄임 이름을 가리킵니다.
보편적인 use 경로 작성법
앞에서 add_to_waitlist까지 모두 가져오지 않고 hosting까지만 가져온 뒤 hosting::add_to_waitlist로 부른 것이 의아할 수 있습니다. 다음처럼 써도 똑같이 동작합니다.
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();
}두 코드는 같은 일을 하지만, 함수를 가져올 때는 앞의 방식이 러스트의 관례입니다. 함수의 부모 모듈을 가져와 부를 때 부모 모듈을 적으면, 전체 경로를 되풀이하지 않으면서도 그 함수가 이 파일에 정의된 것이 아니라는 점이 드러납니다. 위의 코드만 보아서는 add_to_waitlist가 어디에 정의되어 있는지 알기 어렵습니다. 이는 언어가 강제하는 규칙이 아니라 읽기 쉽게 하려는 관례이며, 아래 표가 use의 규칙과 관례를 함께 정리합니다.
LOCAL BINDING · READABLE ORIGIN
use는 현재 스코프에 이름을 바인딩한다
대상을 복사하거나 이동하지 않고, 접근 가능한 경로에 짧은 로컬 이름을 붙입니다. 이름을 어디에 둘지는 언어 규칙이고, 어떤 이름까지 직접 가져올지는 읽기 관용입니다.
언어 규칙 · 스코프와 가시성
바인딩은 선언이 놓인 스코프에 생기며 자식 모듈로 자동 복제되지 않습니다. 원본 경로가 호출 위치에서 접근 가능해야 하고, use는 private 경계를 우회하지 않습니다.
스타일 관용 · 호출부의 출처
함수는 부모 모듈을 가져와 출처를 남기고, 구조체·열거형 같은 타입과 트레이트는 아이템을 직접 가져오는 방식이 관용적입니다. 이름 충돌 시에는 부모 모듈이나 별칭을 씁니다.
| 상황 | 만들어지는 이름 | 규칙과 선택 기준 |
|---|---|---|
| 현재 스코프 | use 선언이 있는 스코프에 로컬 바인딩을 만듭니다. |
자식 모듈은 자동으로 이어받지 않습니다. 필요하면 자식에서 다시 가져오거나 super::hosting처럼 부모의 바인딩을 명시합니다. |
| 가시성 | 접근 가능한 원본 경로와 같은 대상을 가리키는 이름입니다. | 원본 경로의 privacy 검사를 그대로 받으며, 바인딩만으로 대상의 공개 범위를 넓히지 않습니다. |
| 함수 관용 | 부모 모듈 이름을 가져와 모듈을 통해 호출합니다. | 전체 경로 반복은 줄이면서 함수가 로컬 정의가 아님을 호출부에 남기는 스타일 관용입니다. |
| 타입·트레이트 관용 | HashMap, Write처럼 아이템 이름을 직접 가져옵니다. |
타입 표기를 간결하게 하고, 트레이트 메서드를 사용할 때 필요한 트레이트를 스코프에 둡니다. 언어가 강제하는 가져오기 모양은 아닙니다. |
| 이름 충돌 | 부모 모듈을 남기거나 as로 새 로컬 이름을 만듭니다. |
두 방법 모두 유효합니다. 별칭은 IoResult처럼 출처나 역할이 읽히게 정합니다. |
| 외부 크레이트 | Cargo가 호출자에게 바인딩한 크레이트 이름에서 경로가 시작됩니다. | 의존성 선언이 크레이트를 연결하고 use는 그 안의 이름을 현재 스코프에 묶습니다. 의존성 이름을 바꾸면 첫 세그먼트도 바뀝니다. |
중첩 self |
공통 부모와 자식 아이템을 한 선언에서 함께 바인딩합니다. | self는 중괄호 앞의 부모 경로 자체를 뜻합니다. 중첩은 중복만 접고 각 원본 경로의 의미는 유지합니다. |
| 글롭 | *가 경로 아래의 접근 가능한 이름들을 한꺼번에 가져옵니다. |
출처가 흐려지고 의존성 업데이트가 새 충돌을 만들 수 있습니다. 테스트나 의도적으로 설계한 프렐루드처럼 경계가 분명한 곳에 제한합니다. |
- 현재 스코프
- 선언이 놓인 스코프에만 로컬 이름이 생깁니다.
- 자식 모듈에서는 다시 가져오거나 부모 바인딩을 명시합니다.
- 가시성
- 원본 경로의 privacy 검사를 그대로 받습니다.
use는 private 경계나 공개 범위를 바꾸지 않습니다.- 함수 관용
- 부모 모듈을 가져와 모듈 이름을 통해 호출합니다.
- 함수의 출처를 호출부에 남기는 관용이지 언어 규칙은 아닙니다.
- 타입·트레이트 관용
- 아이템 이름을 직접 가져오는 방식이 관용적입니다.
- 타입 표기와 트레이트 메서드 사용을 간결하게 합니다.
- 이름 충돌
- 부모 모듈을 남기거나
as별칭을 사용합니다. - 별칭은 출처나 역할이 드러나는 이름으로 정합니다.
- 외부 크레이트
- Cargo가 호출자에게 바인딩한 크레이트 이름에서 시작합니다.
- 의존성 연결과 로컬 이름 바인딩은 서로 다른 단계입니다.
- 중첩
self - 공통 부모 경로 자체와 자식 아이템을 함께 가져옵니다.
- 경로 의미는 유지하고 반복되는 접두사만 접습니다.
- 글롭
*는 접근 가능한 이름을 한꺼번에 가져옵니다.- 출처와 향후 충돌을 숨기므로 목적이 분명한 범위에 제한합니다.
검토 순서: 선언 위치 → 원본 경로의 접근 가능성 → 호출부에서 보일 출처 → 충돌과 유지보수 위험. 문법상 가능함과 관용적으로 읽기 좋음을 구분합니다.
반면 구조체나 열거형 같은 다른 아이템을 가져올 때는 전체 경로를 적는 것이 관례입니다. 다음은 표준 라이브러리의 HashMap 구조체를 바이너리 크레이트의 스코프로 가져오는 관례적인 코드입니다.
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}이 관례에는 특별한 까닭이 없으며, 그렇게 쓰는 습관이 생겼고 사람들이 그 방식으로 러스트 코드를 읽고 쓰는 데 익숙해졌을 뿐입니다. 다만 이름이 같은 아이템 둘을 한 스코프로 가져올 때는 이 관례를 따를 수 없습니다. 러스트가 허용하지 않기 때문입니다. 다음 코드는 서로 다른 모듈에 있는 이름이 같은 두 Result 타입을, 부모 모듈을 적어 구분합니다.
use std::fmt;
use std::io;
fn function1() -> fmt::Result {
// --생략--
Ok(())
}
fn function2() -> io::Result<()> {
// --생략--
Ok(())
}부모 모듈로 두 Result를 구분했습니다. 대신 use std::fmt::Result와 use std::io::Result를 함께 쓰면 한 스코프에 Result가 둘이 되어, 러스트는 어느 Result를 뜻하는지 알 수 없습니다.
as 키워드로 새로운 이름 제공하기
이름이 같은 타입 둘을 가져오는 또 다른 방법은, 경로 뒤에 as와 새 이름을 적어 별칭(alias)을 붙이는 것입니다. 아래 코드에서 function1의 Result는 std::fmt::Result를, function2의 IoResult<()>는 std::io::Result<()>를 뜻합니다. std::fmt::Result는 성공 값이 ()로 정해져 있어 꺾쇠괄호 없이 쓰고, std::io::Result는 성공 값의 타입을 받으므로 <()>를 붙입니다.
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --생략--
Ok(())
}
fn function2() -> IoResult<()> {
// --생략--
Ok(())
}두 번째 use에서 std::io::Result에 IoResult라는 이름을 붙여, 앞에서 가져온 std::fmt의 Result와 겹치지 않게 했습니다. 부모 모듈로 구분하는 방식과 as로 이름을 바꾸는 방식은 모두 관례에 맞으므로 원하는 쪽을 쓰면 됩니다. as는 타입을 바꾸거나 새 타입을 만드는 것이 아니라 가져온 이름을 구분할 뿐이므로, 별칭도 원래의 Result를 그대로 가리킵니다.
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();
}이렇게 바꾸기 전에는 바깥 코드가 add_to_waitlist를 부르려면 restaurant::front_of_house::hosting::add_to_waitlist() 경로를 써야 했고, 그러려면 front_of_house도 pub이어야 했습니다. 이제 pub use가 루트 모듈에서 hosting을 다시 내보냈으므로, 바깥 코드는 restaurant::hosting::add_to_waitlist()를 쓸 수 있습니다. 다만 pub use가 원래 아이템의 공개 범위를 마음대로 넓힐 수는 없어서, 다시 내보내는 쪽이 원래 경로에 접근할 수 있어야 하고 내보낼 아이템도 공개되어 있어야 합니다.
RE-EXPORT · API BOUNDARY
pub use로 만든 공개 경로도 원본의 가시성을 지킨다
공개 가능한 이름을 새 스코프에서 다시 내보내 사용자가 의존할 경로를 만듭니다. private 내부 모듈은 숨길 수 있지만 private 아이템 자체를 외부 공개로 승격할 수는 없습니다.
내부 모듈 트리
구현자는 접객 영역 아래에 공개 hosting 모듈을 두되 그 조상 모듈은 private으로 유지할 수 있습니다. 루트의 재내보내기 선언은 내부에서 접근 가능한 원본 경로를 해석합니다.
외부 공개 API
사용자는 크레이트 루트에서 재내보낸 hosting 경로를 사용합니다. 원래 조상 모듈은 공개되지 않으며, 내부 이동 시 재내보내기 한 곳을 고쳐 공개 경로를 유지할 수 있습니다.
| 검토 항목 | 가능한 설계 | 남는 제약 |
|---|---|---|
use |
현재 스코프에서 사용할 private 로컬 바인딩을 만듭니다. | 그 이름은 외부 API가 아니며 자식 모듈에 자동으로 복제되지 않습니다. |
pub use |
가져온 이름을 재내보내 새 공개 API 경로를 만듭니다. | 재내보내기 선언이 원본 경로에 접근할 수 있어야 하며 대상도 공개 범위를 충족해야 합니다. |
| private 조상 | private 모듈 안의 공개 아이템을 접근 가능한 위치에서 새 공개 경로로 재내보낼 수 있습니다. | 재내보내기는 원래 조상을 공개하지 않습니다. 외부 사용자는 private 조상을 지나는 원래 경로를 쓸 수 없습니다. |
| private 아이템 | 같거나 더 좁은 제한 범위 안에서만 해당 가시성에 맞는 이름을 다시 바인딩할 수 있습니다. | private 또는 크레이트 한정 아이템을 단순히 pub use하여 외부 공개로 넓힐 수 없습니다. |
| API 이름 | as 별칭으로 사용자의 분야 언어에 맞는 공개 이름을 제공할 수 있습니다. |
별칭도 동일한 원본 가시성 검사를 받으며, 공개 이름 변경은 사용자에게 API 변경이 됩니다. |
| 중첩 재내보내기 | 중괄호와 self로 공통 경로의 여러 공개 이름을 묶을 수 있습니다. |
중첩 문법은 선언만 압축합니다. 각 대상의 접근 가능성과 공개 가능 범위는 따로 검사됩니다. |
| 글롭 재내보내기 | *로 접근 가능한 여러 이름을 공개 표면에 포함할 수 있습니다. |
의존성이나 내부 모듈의 새 공개 이름이 API에 뜻밖에 추가될 수 있어 의도적인 프렐루드 외에는 명시 목록이 안전합니다. |
| 외부 크레이트 | 의존 크레이트의 공개 이름도 별칭이나 새 모듈 경로 아래에서 재내보낼 수 있습니다. | 사용자는 그 타입과 경로에 의존하므로 의존성 교체·버전 변경까지 공개 API 호환성 판단에 포함해야 합니다. |
use- 현재 스코프를 위한 private 로컬 바인딩입니다.
- 반복 경로와 호출부 출처를 정리하는 내부 도구입니다.
pub use- 가져온 이름을 새 공개 경로에서 다시 내보냅니다.
- 원본 경로 접근과 대상 가시성 조건을 모두 만족해야 합니다.
- private 조상
- 그 안의 공개 아이템을 새 공개 경로로 재내보낼 수 있습니다.
- 원래 조상은 계속 private이며 외부 원래 경로는 막혀 있습니다.
- private 아이템
- 재내보내기만으로 외부 공개 범위까지 넓힐 수 없습니다.
- 재내보내기 가시성은 원본이 허용하는 범위를 넘지 못합니다.
- API 이름
as별칭으로 사용자가 볼 공개 이름을 설계할 수 있습니다.- 공개 이름 변경은 사용자에게 API 변경입니다.
- 중첩 재내보내기
- 중괄호와
self로 공통 접두사를 접습니다. - 각 대상의 가시성 검사는 그대로 따로 수행됩니다.
- 글롭 재내보내기
*는 공개 API가 의도하지 않게 늘어날 위험이 있습니다.- 프렐루드 외에는 명시적인 공개 이름 목록이 안전합니다.
- 외부 크레이트
- 의존 크레이트의 공개 이름도 새 경로로 재내보낼 수 있습니다.
- 의존성 변화까지 공개 API 호환성에 포함해 판단합니다.
공개 API 검토 순서: 재내보내기 위치에서 원본 경로 접근 → 대상의 최대 가시성 → 사용자가 볼 이름과 경로 → 내부 이동·의존성 변경 시 호환성.
위의 표처럼, 바깥의 바이너리는 pub use가 만든 공개 이름 restaurant::hosting을 따라 같은 hosting 모듈에 이르고, 그 안의 공개 함수 add_to_waitlist를 부릅니다. 원래 경로의 조상 front_of_house는 여전히 비공개로 감춰져 있습니다.
다시 내보내기는 코드의 내부 구조와, 그 코드를 쓰는 사람이 생각하는 구조가 다를 때 쓸모가 있습니다. 식당의 직원은 홀과 주방을 나누어 생각하지만, 식당을 찾는 손님은 식당을 그렇게 나누어 생각하지 않습니다. pub use를 쓰면 코드를 쓸 때의 구조와 공개할 때의 구조를 다르게 만들 수 있으므로, 라이브러리를 만드는 사람과 쓰는 사람 모두에게 알맞게 라이브러리를 정리할 수 있습니다. pub use가 크레이트의 문서에 주는 영향은 Crates.io 배포에서 다룹니다.
외부 패키지 사용하기
추리 게임에서는 무작위 수를 만들려고 외부 패키지 rand를 썼습니다. 그러려고 Cargo.toml의 [dependencies] 아래에 다음 줄을 더했습니다.
rand = "0.10.2"Cargo.toml에 rand를 의존성으로 더하면, Cargo가 crates.io에서 rand와 그 의존성을 모두 내려받고 우리 프로젝트에서 rand를 쓸 수 있게 합니다. 그다음 rand의 정의를 패키지의 스코프로 가져오려고, 크레이트 이름 rand로 시작하는 use를 적었습니다.
use rand::prelude::*;
fn main() {
let secret_number = rand::rng().random_range(1..=100);
}use rand::prelude::*;는 rand가 자주 쓰는 항목을 모아 둔 프렐류드에서 공개 항목을 모두 가져오며, 그 안의 RngExt 트레이트 덕분에 random_range 메서드를 부를 수 있습니다. 러스트 커뮤니티가 crates.io에 올려 둔 수많은 패키지도 같은 방법으로 씁니다. 패키지를 Cargo.toml에 적고, 크레이트 이름으로 시작하는 경로를 직접 쓰거나 use로 필요한 아이템을 스코프로 가져오면 됩니다. use가 의존성을 더해 주지는 않으므로, Cargo.toml에 적지 않은 크레이트는 use해도 찾을 수 없습니다.
표준 라이브러리 std도 우리 패키지 바깥의 크레이트입니다. 다만 러스트와 함께 설치되므로 Cargo.toml에 적을 필요가 없고, 경로를 std로 시작해 바로 씁니다. 앞의 HashMap을 가져오는 use std::collections::HashMap;이 표준 라이브러리 크레이트의 이름 std로 시작하는 절대 경로입니다.
중첩 경로를 사용하여 대량의 use 나열을 정리하기
같은 크레이트나 모듈에 정의된 아이템을 여러 개 쓸 때 줄마다 하나씩 use를 적으면 세로로 많은 자리를 차지합니다. 예를 들어 추리 게임의 다음 두 use는 std의 아이템을 가져옵니다.
use std::cmp::Ordering;
use std::io;중첩 경로를 쓰면 같은 아이템을 한 줄로 가져올 수 있습니다. 경로에서 같은 부분을 적고, :: 뒤의 중괄호 안에 다른 부분을 나열합니다.
use std::{cmp::Ordering, io};큰 프로그램에서는 같은 크레이트나 모듈의 아이템을 여럿 가져올 때 중첩 경로로 use를 크게 줄일 수 있습니다. 중첩 경로는 경로의 어느 단계에서든 쓸 수 있으며, 한 경로가 다른 경로의 일부인 경우에 특히 쓸모가 있습니다. 다음 두 use는 std::io와 std::io::Write를 가져옵니다.
use std::io;
use std::io::Write;두 경로에서 같은 부분은 std::io이고, 이는 첫 경로 전체이기도 합니다. 중첩 경로에 self를 넣으면 두 경로를 use 하나로 합칠 수 있습니다.
use std::io::{self, Write};이 한 줄이 std::io와 std::io::Write를 모두 스코프로 가져옵니다.
글롭 연산자
경로에 정의된 공개 아이템을 모두 가져오려면 경로 뒤에 글롭(glob) 연산자 *를 붙입니다. *는 그 경로 바로 아래에 정의된 이름에만 적용되며, 하위 모듈 안의 아이템까지 가져오지는 않습니다.
use std::collections::*;이 use는 std::collections에 정의된 공개 아이템을 모두 지금의 스코프로 가져옵니다. 하지만 글롭을 쓰면 코드에서 쓰는 이름이 어디에 정의되었는지 알기 어려워지므로 조심해서 써야 합니다. 의존성의 새 버전이 공개 이름을 더하면 글롭으로 들어오는 이름도 함께 바뀌어, 우리 코드의 이름과 겹칠 수도 있습니다.
글롭은 테스트할 아이템을 모두 tests 모듈로 가져올 때 자주 쓰며, 이는 테스트 작성 방법에서 다룹니다. 앞의 rand::prelude::*처럼 크레이트가 마련한 프렐류드를 가져올 때도 쓰며, 자세한 내용은 표준 라이브러리 문서에 있습니다. use를 정리할 때는 이름을 짧게 하는 것보다, 그 이름이 쓰이는 스코프, 부르는 곳에서 보이는 출처, 겹칠 때 붙인 별칭의 뜻, 바깥에 약속할 공개 경로를 먼저 생각합니다. 자세한 규칙은 Reference의 use 선언에 있습니다.
더 깊이: 글롭으로 들어온 이름이 겹치면
글롭으로 가져온 이름은 직접 정의하거나 이름을 적어 가져온 이름보다 약합니다. Reference의 use 선언 규칙에 따르면, 같은 이름공간(namespace)에 그 이름의 아이템이나 이름을 적은 use가 있으면 글롭으로 들어온 같은 이름은 가려집니다. 그래서 의존성의 새 버전이 우리 코드에 이미 있는 이름을 공개해도, 우리가 정의한 이름이 그대로 쓰입니다.
두 글롭이 같은 이름을 가져오는 경우는 다릅니다. Reference의 이름 해석 규칙은 이 충돌을 가져오는 순간이 아니라 그 이름을 쓰는 순간에 오류로 봅니다. 곧 use m1::*;와 use m2::*;가 둘 다 Ambig를 가져와도 Ambig를 쓰지 않으면 컴파일되고, 쓰는 곳에서 모호하다는 오류가 납니다. 두 글롭이 다시 내보내기를 거쳐 같은 아이템을 가리킨다면 모호하지 않습니다. 그래서 여러 곳에 글롭을 쓰면, 우리 코드를 고치지 않았는데도 의존성을 올린 뒤에 이 오류가 처음 나타날 수 있습니다.
모든 크레이트에 자동으로 들어오는 표준 라이브러리의 프렐류드도 에디션에 따라 내용이 다릅니다. 표준 라이브러리 문서에 따르면 2015와 2018 에디션은 같은 프렐류드를 쓰고, 2021 에디션은 여기에 TryFrom, TryInto, FromIterator를, 2024 에디션은 다시 Future와 IntoFuture를 더합니다. 그래서 2018 에디션에서는 u8::try_from을 부르려면 use std::convert::TryFrom;이 필요했지만, 2021 에디션부터는 필요 없습니다.
정리
use는 경로에 줄임 이름을 붙이며, 그 이름은use가 있는 스코프에서만 쓸 수 있습니다.use는 공개 여부 검사를 받으므로 비공개 아이템을 쓸 수 있게 해 주지 않습니다.- 함수는 부모 모듈까지 가져와
모듈::함수로 부르고, 구조체와 열거형 같은 다른 아이템은 전체 경로로 가져오는 것이 관례입니다. - 이름이 같은 아이템 둘은 부모 모듈로 구분하거나
as로 별칭을 붙입니다. pub use는 가져온 이름을 다시 내보내, 내부 구조와 다른 공개 경로를 만듭니다.- 외부 패키지는
Cargo.toml에 적은 뒤 크레이트 이름으로 시작하는 경로로 쓰며,std는 적지 않아도 됩니다. - 중첩 경로
{...}와self로 여러use를 합치고, 글롭*는 테스트나 프렐류드처럼 쓰임이 분명할 때 씁니다.
연습 문제
1. 두 별칭
다음 프로그램은 무엇을 출력하나요? FmtResult와 IoResult는 새 타입인가요?
use std::fmt::Result as FmtResult;
use std::io::Result as IoResult;
fn format_ready() -> FmtResult {
Ok(())
}
fn io_ready() -> IoResult<()> {
Ok(())
}
fn main() {
println!("format: {}", format_ready().is_ok());
println!("io: {}", io_ready().is_ok());
}해설 보기
format: true와 io: true를 출력합니다. 두 별칭은 새 타입이 아니라 표준 라이브러리의 원래 Result에 붙인 다른 이름입니다. std::fmt::Result는 성공 값이 ()로 정해진 타입 별칭이므로 FmtResult에 타입 인수를 적지 않았고, std::io::Result는 성공 값의 타입을 받으므로 IoResult<()>처럼 적었습니다.
2. 공개 경로와 원래 경로
pub use crate::front_of_house::hosting;이 있는 레스토랑 라이브러리에서 front_of_house는 비공개입니다. 같은 패키지의 바이너리에서 (가) restaurant::hosting::add_to_waitlist()와 (나) restaurant::front_of_house::hosting::add_to_waitlist()는 각각 컴파일되나요? (다) 라이브러리 안의 자식 모듈에서 hosting::add_to_waitlist()라고 쓰면 어떻게 되나요?
해설 보기
(가)는 pub use가 만든 공개 경로이므로 컴파일됩니다. (나)는 원래 경로의 조상 front_of_house가 비공개이므로 E0603 오류로 막힙니다. 다시 내보내기는 같은 hosting에 공개 이름을 하나 더 만들 뿐, 비공개 조상을 공개로 바꾸지 않습니다. (다)는 pub use도 크레이트 루트 스코프에 이름을 묶은 것이므로, 자식 모듈에서는 hosting을 찾지 못해 E0433 오류가 납니다. 자식 모듈에서는 super::hosting::add_to_waitlist()나 crate::hosting::add_to_waitlist()로 씁니다.
3. use 줄이기
다음 세 줄을 use 하나로 합쳐 보세요. use std::collections::HashMap;, use std::collections::HashSet;, use std::collections;
해설 보기
use std::collections::{self, HashMap, HashSet};로 합칠 수 있습니다. 같은 부분인 std::collections를 앞에 적고, 그 경로 자체는 self로, 나머지 두 아이템은 이름으로 중괄호 안에 나열합니다.
다음 글 파일 기반 모듈 분리에서는 커진 모듈을 다른 파일과 폴더로 나누면서도 모듈 트리와 경로를 그대로 유지하는 방법을 살펴봅니다.