이야기의 배경:
C++나 Java와 같은 언어에서는 접근 수정자(public, private, protected)가 클래스의 멤버 가시성을 보장하지만, 그 유연성으로 인해 API 사용 시 오류를 예방하지 못하는 경우가 많습니다. 러스트에서는 초기 버전부터 접근 제어 시스템을 엄격하고 모듈화하여 내부 세부정보가 외부로 "유출"되는 것을 제한하고자 했습니다.
문제:
구조체의 일부는 외부 코드로부터 숨겨야 하는 경우가 많습니다. 예를 들어, 필드는 비공개로 설정하고, 외부에는 메서드만 노출합니다. 접근을 제한하지 않으면 구조체의 불변 조건을 의도치 않게 파괴할 수 있습니다(예: 내부 Vec를 직접 노출). 구조체를 무분별하게 공개하면 API가 취약해집니다.
해결책:
러스트에서는 기본적으로 모든 것이 비공개입니다. pub 키워드는 명시적 내보내기 용도로 사용됩니다: 구조체는 별도로 가시화될 수 있고, 필드는 숨길 수 있습니다. 메서드는 각각 pub으로 선언되거나 비공개로 설정됩니다. 또한, pub(crate) 또는 pub(super)와 같은 비표준 형태는 접근 수준을 세밀하게 조정할 수 있게 합니다.
코드 예:
mod domain { pub struct User { pub name: String, age: u32, // 비공개 필드 } impl User { pub fn new(name: String, age: u32) -> Self { Self { name, age } } pub fn age(&self) -> u32 { self.age } } } use domain::User; fn main() { let u = User::new("Eve".to_string(), 24); println!("{} {}", u.name, u.age()); // u.age — 접근 오류! 필드는 모듈 외부에서 닫혀 있음 }
주요 특징:
구조체를 pub으로 만들 수 있지만 모든 필드는 비공개로 둘 수 있을까? 그렇다면 모듈 밖에서 어떻게 인스턴스를 생성할 수 있을까?
예. 일반적으로 그렇게 합니다: 구조체는 pub으로 설정하고 필드는 비공개로 두며, 생성은 공개 생성자를 통해서만 가능합니다(예: pub fn new...).
pub struct Foo를 선언할 때 구조체의 필드가 외부 코드에서 보이나?
아니요, 기본적으로 각 필드는 여전히 비공개입니다. 필드에 대해 pub을 명시적으로 적어야 합니다. pub struct는 type만 가시적으로 만듭니다.
enum에 대한 pub도 동일하게 작동하나?
enum에 대한 pub는 모든 변형에 적용되지만, 변형 내의 관련 데이터(예: Variant(value: T) 내의 필드)도 여전히 접근 가능하려면 pub을 명시해야 합니다.
라이브러리에서 구조체가 pub struct Config로 선언되었고 모든 필드도 pub으로 설정되어 사용자에게 "보이게" 되었습니다. 결과적으로, 외부 코드가 상태를 임의로 변경할 수 있어 불변 조건을 파괴하고, 아무 이유 없이 panic이 발생할 수 있었습니다.
장점:
단점:
구조체 Config는 pub으로 설정하고 모든 필드는 비공개로 두었습니다. 설정은 빌더 메서드, 기본 생성자 또는 setter/getter 함수를 통해서만 이루어집니다. 모듈 밖에서는 불변 조건을 파괴할 수 없습니다.
장점:
단점: