Super로 상대 경로 시작하기
super로 상대 경로를 시작하는 것은 파일 시스템에서 .. 구문을 이용하는 것과 비슷하다.
이전의 예시에서 셰프가 잘못된 주문을 고치고 손님에게 개인적으로 가져다주는 fix_incorrect_order 함수를 만든다고 가정해보자.
fn serve_order() {}
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::serve_order();
}
fn cook_order() {}
}
fix_incorrect_order 함수는 back_of_house 함수 안에 있으므로 back_of_house 의 부모 모듈(crater)에게 접근하기 위해 super 키워드를 사용할 수 있다. 그리고 부모 모듈에서 serve_order를 찾을 수 있다.
Public 구조체와 열거형
pub 키워드를 사용하여 구조체를 public으로 만들 수 있다. 이때, 구조체의 필드까지 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");
}
위 예제에서 손님은 toast는 원하는 대로 주문할 수 있지만, seasonal_fruit는 주문할 수 없다.
이와는 대조적으로 public 열거형은 그 안의 내용까지 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키워드로 한번에 스코프로 가져와 로컬 item처럼 호출 할 수 있다.
use키워드는 파일 시스템에서 심볼릭 링크(symbolic link)를 사용하는 것과 비슷하다.
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();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use self::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
use crate로 시작되는 경로는 절대경로, use self로 시작되는 경로는 상대 경로이다.
위와 같이 user crate::front_of_house::hosting을 크레이트 루트 안에 사용하면, hosting은 그 스코프에서 정의된 것처럼 유효한 이름이 된다. use로 가져와진 path도 역시 privacy인지 검사한다.
앞서 본 듯이 use 키워드는 모듈에서 포함 관계를 명확히 하기 위해 부모 모듈의 경로를 관용적으로 사용한다.
하지만 구조체,열거형과 같은 다른 item에서 use 키워드를 사용할 때는 특정 경로를 다 적어주는 것이 관용적이다.
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}
예외적으로 같은 이름을 가진 2개의 item에 use 구문을 사용하는 경우, 러스트가 이를 방지하므로 상위 모듈을 가져온다.
use std::fmt;
use std::io;
fn function1() -> fmt::Result {
// --snip--
}
fn function2() -> io::Result<()> {
// --snip--
}
동일한 모듈에 정의된 여러 항목을 사용하는 경우, 파일의 줄 수가 많아진다. 이때,
중첩 경로를 사용하여 동일한 항목 중괄호로 묶어 한 줄의 범위로 가져올 수 있다. 자주 쓰이니 꼭 기억하자!
// before
use std::cmp::Ordering;
use std::io;
// after
use std::{cmp::Ordering, io};
또한, 공통 부분을 하나로 병합하기 위해 self키워드를 사용할 수 있다.
// before
use std::io;
use std::io::Write;
// after
use std::io::{self, Write};
경로에 정의된 모든 항목을 스코프로 가져오려면 글로브 오퍼레이터(*)로 표기할 수 있다.
use std::collections::*;
As로 별칭 지정하기
use뒤에 as로 새 이름을 지정해 주는 방법도 있다. as로 지어진 모듈의 이름은 로컬에서만 사용할 수 있다.
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --snip--
}
fn function2() -> IoResult<()> {
// --snip--
}
Re-exporting
다른 스코프에서도 자신의 스코프에서 use 키워드를 이용해 선언된 item을 쓸 수 있게 하려면 pub과 use키워드를 같이 사용하면 되고, 이를 re-exporting이라고 한다.
pub mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {
println!("Hello!");
}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
위 코드는 src폴더 안에 lib.rs라는 파일에 저장되어 있다. main.rs에서 front_of_house모듈을 사용할 수 있게 해보자.
src
└── lib.rs
│ ├── front_of_house
│ └── hosting
└── main.rs
use new::front_of_house::hosting as host;
fn main() {
host::add_to_waitlist();
}
lib.rs에서 hosting모듈을 pub use하여 외부에서도 사용 가능하게 했으므로, main.rs에 다음과 같이 선언하고 host라는 이름을 붙여주었다. main함수에서 add_to_waitlist 함수를 불러온다.
외부 패키지 사용
외부 패키지를 사용하려면 crates.io에서 사용하려는 패키지를 다운로드 받고, Cargo.toml에 사용하려는 패키지와 종속성을 추가한다. 표준 라이브러리(std)는 기본적으로 제공되기 때문에 Cargo.toml을 변경할 필요가 없다. 하지만 스코프 범위로 가져오려면 use 키워드를 사용해야 한다.
모듈을 다른 파일로 분리하기
모듈이 커지면 별도의 파일로 분리해서 사용하는 것이 코드 관리에 더 용이하다.
pub mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {
println!("Hello!");
}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
앞서 본 다음 코드는 src/lib.rs에 있는 내용이다.
front_of_house에 들어있는 모듈들을 각각의 파일로 나누어 보자.
- src/lib.rs
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
front_of_house의 선언만 남기고 그 안의 내용은 분리하려고 한다.
- src/front_of_house.rs
pub mod hosting;
블록을 사용하지 않고 뒤에 세미콜론을 사용하는 것은 러스트에게 모듈과 같은 이름을 가진 다른 파일에서 모듈의 내용만 로드하도록 지시한다. 그래서 간단히 hosting 모듈만 선언해준다.
- src/front_of_house.hosting.rs
pub fn add_to_waitlist() {
println!("called add_to_waitlist() function!");
}
hosting모듈의 내용인 add_to_waitlist()함수이다.
이제 main.rs에서 lib.rs의 eat_at_restaurant()함수를 호출해보자.
use new::eat_at_restaurant;
fn main() {
eat_at_restaurant();
}
컴파일 결과 잘 동작하는 것을 확인할 수 있다.
'러스트' 카테고리의 다른 글
공통 컬렉션(Common Collection) - 스트링 (0) | 2022.03.14 |
---|---|
공통 컬렉션(Common Collections) - 백터 (0) | 2022.03.14 |
패키지, 크레이트, 모듈(1) (0) | 2022.03.11 |
열거형과 Match (0) | 2022.03.11 |
구조체 (0) | 2022.03.10 |