rokdocs
v0.1

5.5. use (가져오기)

use 키워드 (키워드) 는 다른 모듈의 항목을 현재 모듈의 가시 이름 공간으로 끌어오는 구문입니다.

5.5.1. 기본 형태

use_stmt    ::= "use" use_tree ";"
use_tree    ::= path "::" "*"
              | path "::" "**"
              | path "::" "{" use_tree ("," use_tree)* ","? "}"
              | path ("as" identifier)?
path        ::= path_root ("::" identifier)*
path_root   ::= "pkg" | "sup" | identifier

glob (*, **) 에는 as 별칭을 붙이지 않습니다. 한 번에 여러 항목을 끌어오기 때문에 단일 별칭이 의미를 갖기 어렵기 때문입니다. 그래서 path ("as" identifier)? 는 단일 항목 import 에만 적용됩니다.

use foo::bar;
use rok::std::time::Duration;
use pkg::geom::Point;

기본 구조는 use 다음에 경로가 오고 마지막에 ; 로 마무리하는 형태입니다. 이때 경로의 마지막 식별자가 현재 모듈에서 그 항목의 이름이 됩니다. use 한 뒤로는 bar, Duration, Point 같은 짧은 이름으로 편하게 참조할 수 있습니다.

5.5.2. 다중 import: {...}

같은 prefix 를 가진 여러 항목은 한 줄로 묶어서 적을 수 있습니다.

use foo::{a, b, c};
use rok::std::time::{Duration, Instant};

{..} 의 각 원소는 그룹의 해소된 prefix 를 잇습니다. prefix 가 비어도 됩니다 (pkg::{..}, 루트에 닿는 sup::{..}). 그래서 use p::{a, b} 는 어느 모듈에서든 정확히 다음과 같습니다.

use foo::a;
use foo::b;
  • 그룹은 중첩할 수 있고, *, **, as 를 담을 수 있습니다 (use foo::{bar::{x, y as z}, baz::*};).
  • 그룹 안의 self 는 에러입니다.
  • 각 잎은 항목, enum 변형, 모듈 중 하나로 해소되어야 합니다. 아니면 그 잎 위치에 "unresolved import" 에러입니다.

5.5.3. 별칭: as

가져온 항목의 이름은 as 키워드로 변경할 수 있습니다.

use foo::very_long_name as short;
use rok::std::collections::Dict as Map;

as 뒤에 새 이름을 붙이는 방식이며, 이렇게 하면 현재 모듈에서는 새 이름만 보이고 원래 이름은 보이지 않게 됩니다.

다중 import 안에서도 함께 쓸 수 있습니다.

use foo::{a as alpha, b, c as charlie};

5.5.4. glob: * (얕은)

모듈의 모든 가시 항목을 한 번에 가져오는 방법입니다.

use foo::*;                    // foo 의 가시 항목 전부

여기에는 몇 가지 규칙이 있습니다. 먼저 * 는 반드시 마지막 토큰이어야 해서, use foo::*::bar 같은 형태는 ERROR 가 됩니다. 그리고 가져오는 항목은 호출자가 볼 수 있는 가시성을 가진 것뿐이라서 (가시성), pub 이거나 같은 패키지면 pub(pkg) 등 reach 가 호출자를 포함하는 항목들만 대상이 됩니다. 또한 foo 의 직접 자식만 가져오기 때문에, 서브 모듈의 항목은 가져오지 않습니다 (그 역할은 ** 가 담당합니다). 블록의 glob use 는 그 블록에 선언한 항목의 머리에도 닿습니다 (3.9.1). 모듈이 정의한 항목은 glob 으로 가져온 같은 이름의 항목을 이깁니다: glob 이 양보하며 아무것도 보고하지 않습니다 (그 이름을 적은 import 는 대신 에러입니다, 5.5.12).

5.5.5. 재귀 glob: ** (깊은)

서브 모듈까지 재귀적으로 가져오고 싶을 때 사용하는 형태입니다.

use foo::**;                   // foo 의 모든 항목 + foo 의 자식 모듈의 모든 항목 + ...

서브 모듈을 거쳐 모든 가시 항목까지 한 번에 가져오기 때문에, 얕은 glob (*) 보다 범위가 훨씬 광범위합니다. 큰 라이브러리의 prelude 형태로 자주 활용됩니다. 재귀 glob 은 모듈 항목과 enum 변형을 가져오며, 타입의 연관 항목은 결코 가져오지 않습니다: 묵시 use rok::core::**; (5.5.10) 아래에서 맨 MAX 는 Duration::MAX 를 가리키지 않습니다.

5.5.6. glob / 재귀 glob 의 충돌

여러 glob 이 같은 이름을 가져오게 되면 충돌이 발생합니다.

use foo::*;
use bar::*;
// 둘 다 'item' 이라는 이름이 있으면, 그 이름은 모호해서 사용 시 ERROR.

이러한 경우에는 하나를 명시 import 하거나 별칭을 부여해서 해소하면 됩니다.

use foo::item;                 // 명시 - foo::item 만 가시
use bar::item as bar_item;      // 별칭 - 둘 다 다른 이름으로

5.5.7. 경로의 시작점

경로의 첫 식별자는 경로 의 규칙을 따르며, 크게 세 가지 경우로 나뉩니다. pkg:: 는 현재 패키지의 루트부터 시작하고, sup:: 는 부모 모듈부터 시작하며 여러 단계를 올라갈 때는 sup::sup::... 처럼 연쇄해서 쓸 수 있습니다. 그 외에 일반 식별자는 첫 식별자가 현재 가시한 이름일 때 사용 가능합니다 (자식 모듈, 이미 use 한 이름 등). 같은 모듈의 자식 호출은 식별자 자체로 충분하기 때문에 별도의 self:: 는 두지 않았습니다.

enum 변형 가져오기

enum 의 변형은 그 enum 아래의 항목이므로 use 로 가져올 수 있습니다. 또한 use 경로는 현재 가시한 타입 이름으로 시작할 수 있습니다.

use Shape::{Circle};                // 변형 하나
use Shape::{Square as Sq};          // 별칭
use Shape::*;                       // 모든 변형
use Result::*;                      // 가시한 타입 이름으로 시작

암묵 use rok::core::**; (5.5.10) 가 Result 아래의 변형까지 가져오므로 Ok / Err 는 접두 없이 쓸 수 있습니다. 패턴에서 맨 이름이 가져온 변형으로 해소되면, 그 이름은 새 바인딩이 아니라 그 변형과 매칭합니다.

match r {
    Ok(v)  => v,
    Err(e) => fallback(e),
}

5.5.8. use 의 위치

use 는 모듈 수준이나 함수 본체 수준 어디에서든 등장할 수 있습니다.

// 모듈 수준 - 그 모듈 전체에서 가시
use foo::bar;

fn f() {
    // 함수 안 - 그 함수 안에서만 가시
    use foo::baz;
    let x = baz();
}

함수 안에서 쓰인 use 는 그 함수의 지역 import 라서 외부에는 노출되지 않습니다. 따라서 가시성 키워드 (pub) 도 의미를 갖지 못합니다.

5.5.9. use 의 가시성

use foo::bar;                   // 모듈 비공개 - 같은 모듈 안에서만 보임
pub use foo::bar;               // 외부 노출 - 재내보내기
pub(pkg) use foo::bar;          // 같은 패키지 내부만 노출

pub use 는 재내보내기에 해당합니다. 자세한 내용은 가시성 에서 정의합니다.

5.5.10. rok::core 자동 import

컴파일러는 모든 rok 소스 시작 시점에 묵시적으로 use rok::core::**; 를 적용합니다. 그래서 표준 라이브러리의 foundation tier 트리가 자동으로 가시화되며, 사용자가 별도로 use 를 적지 않아도 rok::core 의 항목 (가장 흔한 컬렉션 타입, 트레잇, 연산자 등) 을 짧은 이름으로 바로 쓸 수 있습니다.

rok::core 외의 두 tier - rok::bare (위험 영역) 와 rok::std (target-dep) - 는 자동 가시에서 제외 되며 명시 import 가 필요합니다. 자세한 내용은 표준 라이브러리 계층 에서 정의합니다.

표준 라이브러리 외의 모든 모듈 - 외부 패키지, 사용자 라이브러리 - 도 명시 import 가 필요합니다. prelude 라는 이름의 모듈을 만들더라도 자동으로 끌려오지는 않습니다. 그것은 어디까지나 라이브러리 작성자의 관습적 이름일 뿐이라서, 사용자 입장에서는 use my_lib::prelude::*; 처럼 명시적으로 가져와야 합니다.

// 라이브러리 측
pub mod prelude {
    pub use pkg::api::rok::*;
    pub use pkg::api::ext::*;
}

// 사용자 측
use my_lib::prelude::*;            // 명시적으로 끌어와야 가시

5.5.11. 같은 모듈 / 항목 두 번 import: 허용

use foo::bar;
use foo::bar;                   // OK - 중복 import 무해

같은 항목의 중복 import 는 별다른 부작용이 없기 때문에 허용합니다. 동일성 검사로 정말 같은 것이라고 확인되면 문제없이 통과합니다.

5.5.12. 다른 모듈에서 같은 이름: 충돌

use foo::Item;
use bar::Item;                  // ERROR - 'Item' 이 이미 import 됨

서로 다른 모듈에서 같은 짧은 이름을 import 하면 충돌이 일어납니다. 이럴 때는 하나를 별칭으로 풀어 주면 됩니다.

use foo::Item;
use bar::Item as BarItem;       // OK

이름을 적은 import (use a::f;, use a::{f}, g 에 대해서는 use a::f as g;) 와, 그 import 가 채우는 이름공간에서 모듈에 정의한 같은 이름의 항목은 컴파일 에러 (E102, 9.9.4) 입니다: 항목이 import 를 보이지 않게 가리기 때문입니다. 다른 이름으로 import 하거나 (use a::f as a_f;) use 를 지웁니다. 같은 이름의 값 항목 옆의 타입 import 는 충돌하지 않으며, glob import 는 모듈의 항목에 양보합니다 (5.5.4).

use shapes::square;
fn square(x: f64) -> f64 { x * x }    // ERROR - `square` is both imported from `shapes::square` and defined in this module

5.5.13. use 의 평가 / 효과

use 는 컴파일 타임의 이름 해소 정보만 변경하기 때문에 런타임 동작에 직접적인 영향을 주지 않습니다. use 자체로는 어떤 코드도 실행되지 않으며, 단지 현재 모듈의 이름 표에 별칭을 추가하는 역할만 합니다.

5.5.14. 모듈 자체를 import

use foo::geom;                  // foo::geom 모듈 자체를 import
let p = geom::Point { ... };    // geom 을 짧은 이름으로 사용

항목뿐만 아니라 모듈 자체도 import 할 수 있습니다. 이렇게 하면 그 모듈의 이름 (마지막 식별자) 이 현재 모듈에서 짧은 이름으로 보이게 되며, 자식 모듈을 거쳐 접근하는 패턴으로 자주 활용됩니다.

GitHub에서 이 페이지 고치기