5.6. 가시성
함수, 타입, 트레잇, 모듈, const, static 같은 각 항목에 가시성을 부여하면 외부 노출 범위를 조절할 수 있습니다.
visibility ::= "pub" ("(" reach ")")?
reach ::= "pkg" | "sub"
5.6.1. 네 단계
가시성은 다음과 같이 네 단계로 나뉩니다.
| 키워드 | 의미 |
|---|---|
| (없음) | 모듈 비공개. 같은 모듈 안에서만. |
pub(sub) | 같은 모듈 트리의 하위 모듈에서만. |
pub(pkg) | 같은 패키지 안에서만. |
pub | 외부 패키지에서도. |
가장 좁은 범위가 기본값인 private 이고, 가장 넓은 범위가 pub 입니다.
pkg 와 sub 은 pub(...) 괄호 안에서만 한정자로 동작하는 컨텍스트 키워드여서, 그 외의 위치에서는 일반 식별자로 쓰입니다 (1.5.4 가시성 한정자 참고).
5.6.2. 기본: 가시성 키워드 없음
가시성 키워드를 적지 않으면 그 항목은 모듈 비공개가 되어 같은 모듈 안에서만 보입니다.
mod m {
fn helper() -> i32 { 42i32 } // 모듈 비공개 (기본)
pub fn api() -> i32 { helper() }
}
let r = m::api(); // OK
let h = m::helper(); // ERROR - 모듈 비공개
비공개 mod 는 그것을 선언한 부모 모듈과, 그 부모의 하위 모듈에서 보입니다.
5.6.3. pub: 가장 넓은 공개
가장 넓은 공개 범위를 원할 때는 pub 을 붙입니다.
pub fn calculate(x: i32) -> i32 { ... }
pub struct Point { pub x: f64; pub y: f64; }
pub trait Display { ... }
이렇게 선언한 항목은 다른 패키지에서도 use 로 가져와 사용할 수 있습니다.
5.6.4. pub(pkg): 패키지 내부
pub(pkg) 는 패키지 내부 공개를 의미합니다.
pub(pkg) fn internal_helper() -> i32 { ... }
같은 패키지 안의 어느 모듈에서나 가시화되지만, 외부 패키지에서는 보이지 않습니다. 의존 패키지와 rok:: 의 각 tier 도 별개의 패키지입니다 (5.7.14).
이 단계는 패키지 내부 라이브러리 도구를 위한 것이라서, 공개 API 는 아니지만 모듈을 가로질러 공유해야 하는 함수와 타입에 사용합니다.
5.6.5. pub(sub): 하위 모듈
pub(sub) 는 모듈 트리의 한 가지 안에서만 공유하고 싶을 때 씁니다.
mod parent {
pub(sub) fn shared_within_subtree() -> i32 { ... }
pub mod child {
pub fn use_it() -> i32 { sup::shared_within_subtree() } // OK
}
}
parent 와 parent 의 모든 자손 모듈에서만 가시화되고, 부모 모듈이나 형제 모듈에서는 보이지 않습니다.
이 단계는 모듈 그룹 내부 도구를 위한 것이라서, 모듈 트리의 한 가지 안에서만 공유하는 용도로 사용합니다.
5.6.6. 단계의 포함 관계
가시성은 단조 증가 lattice 를 이룹니다.
pub ⊇ pub(pkg) ⊇ pub(sub) ⊇ private
pub(sub) 의 포함 관계는 관련 모듈, 즉 정의 모듈 자신과 그 자손 안에서만 의미가 있습니다.
pub는 모든 호출자에게 보입니다.pub(pkg)는 같은 패키지 안에서만 보입니다.pub(sub)는 같은 모듈 트리 안에서만 보입니다.- private 은 같은 모듈에서만 보입니다.
5.6.7. glob import 와 가시성
glob import (*, **, 암묵 use rok::core::** 포함) 가 가져오는 항목은 import 하는 모듈에서 가시한 항목뿐입니다. 즉 reach 가 그 모듈을 포함해야 끌려오며, 보이지 않는 항목은 이름을 가리거나 충돌을 일으키지도 않습니다. 별도의 per-item glob-block 표시는 두지 않으니, 외부 노출 표면을 좁히고 싶다면 별도의 prelude 모듈을 만들고 pub use 로 큐레이션하는 패턴을 쓰면 됩니다.
5.6.8. struct 필드의 가시성
각 필드에는 별도로 가시성을 부여할 수 있습니다.
struct Account {
pub id: i64; // 외부 읽기 가능
pub balance: f64; // 외부 읽기 가능
secret: str; // 모듈 비공개
}
이때 부여한 필드 가시성은 struct 자체의 가시성과는 별개로 동작합니다.
pub struct Counter { // struct 자체는 외부 가시
count: i32 = 0i32; // 필드는 모듈 비공개 (기본)
}
let c = Counter { count: 0i32 }; // ERROR - 필드 비공개라 외부에서 직접 만들 수 없음
let c = Counter::new(); // OK - 팩토리 메서드 (있다면)
이는 타입은 외부에 노출하되 직접 인스턴스화는 막는 표준 패턴입니다 (newtype, opaque type).
tuple struct 의 필드
tuple struct 의 각 필드도 자기 가시성을 가지며, 기본은 비공개입니다.
pub struct S(pub i32, i32); // 0 번은 pub, 1 번은 비공개
S(a, b)로 만들려면 사용처에서 모든 필드가 보여야 합니다. 비공개 필드가 하나라도 있으면 그 가시성 범위 밖에서는 생성자 함수를 씁니다 (NonZero::new).x.N을 읽거나 대입하려면 N 번 필드가 보여야 합니다.- 패턴
S(p0, p1, ..)에서 하위 패턴이_가 아닌 자리는 보여야 합니다. 이름 있는 필드의 struct 패턴도 같습니다 (건드리는 필드만 검사). pub바로 뒤의(는 가시성 제한 (pub(pkg)등) 으로 읽습니다. 튜플 타입의 필드를 공개하려면 괄호를 한 번 더 씁니다:struct S(pub ((i32, i32)));.
5.6.9. enum 변형의 가시성
변형은 별도의 가시성을 갖지 않으며, enum 의 가시성을 그대로 따릅니다. 변형 앞에 가시성 키워드를 붙이면 컴파일 에러입니다.
pub enum Shape {
Circle(f64), // pub - Shape 를 따름
Square(f64),
}
pub enum Bad {
pub A, // ERROR - 변형에는 가시성을 적지 않음
}
변형의 payload 필드에도 필드별 가시성이 없으며, enum 을 따릅니다. struct 필드와 달리 변형을 하나만 숨기면 외부의 match 가 완전성을 만족할 수 없으므로 이렇게 정합니다. 표준 라이브러리의 pub enum Result<T, E> { Ok(T), Err(E) } 도 이 규칙으로 Ok / Err 가 공개됩니다.
5.6.10. impl 메서드의 가시성
impl 의 고유 impl 메서드는 기본적으로 모듈 비공개여서, 외부에 노출하려면 pub 으로 명시해야 합니다.
impl Account {
pub fn balance(self) -> f64 { self.amount }
fn _internal_check(self) { ... }
}
트레잇 impl 의 메서드는 그 트레잇의 가시성을 따르기 때문에 별도로 표시할 수 없습니다.
5.6.11. use 의 가시성
use 의 import 도 가시성을 가집니다.
use foo::bar; // 모듈 비공개 (기본)
pub use foo::bar; // 재내보내기 - 외부에서도 보임
pub(pkg) use foo::bar; // 패키지 내부만
재내보내기는 use 의 가시성 절과 결합해 외부 노출 표면을 결정합니다.
5.6.12. 가시성의 위치
가시성 키워드는 항목 선언의 첫 토큰으로 등장합니다.
pub fn f() { ... }
pub(pkg) fn g() { ... }
pub struct S { ... }
pub mod m { ... }
pub const X: i32 = 0;
pub static Y: i32 = 0;
pub use foo::bar;
pub trait T { ... }
fn, struct, enum, union, trait, impl (impl 자체에는 붙이지 않고 메서드별로 붙입니다), mod, const, static, use, type (별칭) 의 모든 선언 형태에 부착할 수 있습니다.
5.6.13. 가시성과 이름 해소
use 와 결합해 한 항목이 현재 모듈에서 보이려면 다음 두 조건을 모두 만족해야 합니다.
- 항목의 가시성이 현재 모듈에서 도달 가능해야 합니다. 경로의 모든 모듈 마디도 각자 보여야 합니다 (
a::b::f는a,b,f가 모두 보여야 함). - 항목이 직접 가시 (자식 모듈이나
use로 가져온 이름) 해야 합니다.
두 조건을 모두 만족하면 그 항목을 짧은 이름으로 쓸 수 있습니다.
가시성이 부족한 항목은 컴파일러 진단이 보이지 않는 이유를 보고합니다.
ERROR: 'foo::secret' is not visible from this module.
It is declared as private - only visible within 'foo'.
To use it externally, add 'pub' or other visibility keyword.