Private 필드
Coddy Rust 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 10번째.
이전 레슨에서는 구조체(struct), 필드, 메서드 등 모든 것을 공개(public)로 설정했습니다. 하지만 진정한 캡슐화란 데이터에 접근하는 방법을 제어하는 것을 의미합니다. Rust에서는 구조체는 공개로 유지하면서 필드는 비공개(private)로 유지할 수 있습니다.
잔고가 절대 음수가 되어서는 안 되는 Wallet을 생각해 봅시다. 필드가 public이면, 누구든지 어떤 값으로든 설정할 수 있습니다:
// wallet.rs
pub struct Wallet {
balance: f64, // pub이 없으면 private입니다!
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
Wallet은 public이지만, balance에는 pub 키워드가 없다는 점에 유의하세요. 이는 모듈 외부의 코드가 생성자를 사용하여 Wallet을 생성할 수는 있지만, balance 필드를 직접 읽거나 수정할 수는 없음을 의미합니다:
// main.rs
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // 오류! 필드가 private입니다
// w.balance = -50.0; // 오류! private 필드에 접근할 수 없습니다
}
이것이 캡슐화의 기초입니다. struct는 자신의 데이터를 스스로 제어합니다. 외부 코드는 사용자가 제공하는 메서드를 거쳐야만 하며, 이는 검증, 로깅 또는 기타 로직을 추가할 수 있음을 의미합니다. 이를 통해 데이터는 유효하지 않은 상태로부터 보호됩니다.
이어지는 레슨에서는 게터(getter) 및 세터(setter) 메서드를 통해 이 프라이빗 데이터에 대한 제어된 접근을 제공하는 방법을 배우게 됩니다.
챌린지
쉬움모듈 내부에 민감한 데이터를 보호하여 캡슐화를 보여주는 온도 센서 시스템을 구축해 보겠습니다.
코드를 구성하기 위해 두 개의 파일을 생성합니다:
sensor.rs:location(String)과reading(f64)이라는 두 개의 필드를 가진TemperatureSensor구조체를 정의합니다. 이 구조체는 다른 파일에서 사용할 수 있도록 public이어야 하지만, 두 필드는 모두 private으로 유지해야 합니다. 외부 코드에서 센서의 데이터에 직접 접근하거나 수정할 수 없어야 합니다. 위치 이름과 초기 온도 값을 매개변수로 받는 publicnew생성자를 추가하세요.main.rs: 센서 모듈을 가져와서 생성자를 사용하여TemperatureSensor를 생성합니다. 필드가 private이므로 직접 출력할 수는 없습니다. 대신 센서가 성공적으로 생성되었음을 나타내는 확인 메시지를 출력하세요.
이 챌린지는 private 필드의 핵심 개념에 집중합니다. 구조체 자체는 접근 가능하지만 내부 데이터는 보호됩니다. 외부 코드는 여러분이 제공하는 메서드(이 경우에는 생성자)를 통해서만 센서와 상호작용할 수 있습니다.
출력은 다음 형식을 정확히 따라야 합니다:
Sensor created for: {location}출력을 위해 위치 정보에 접근하려면, 필드 자체가 private이므로 new 함수가 센서를 반환하기 전에 이 메시지를 출력하도록 해야 합니다.
예를 들어, 위치가 "Kitchen"이고 온도가 22.5인 센서를 생성하면 출력은 다음과 같습니다:
Sensor created for: Kitchen두 개의 입력을 받게 됩니다: 위치 이름과 초기 온도 값입니다.
치트 시트
Rust에서는 캡슐화를 달성하기 위해 구조체는 공개(public)로 만들면서 필드는 비공개(private)로 유지할 수 있습니다. 이는 외부 코드에서 내부 데이터에 직접 접근하거나 수정하는 것을 방지합니다.
필드를 비공개로 만들려면 간단히 pub 키워드를 생략하면 됩니다:
pub struct Wallet {
balance: f64, // pub 없음 = 비공개 필드
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
이 예제에서 Wallet은 공개(모듈 외부에서 사용 가능)이지만, balance는 비공개(외부에서 직접 접근 불가)입니다.
외부 코드는 공개 생성자를 사용하여 인스턴스를 생성할 수 있지만, 비공개 필드를 읽거나 수정할 수는 없습니다:
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // 에러! 필드가 비공개임
// w.balance = -50.0; // 에러! 비공개 필드에 접근할 수 없음
}
이러한 캡슐화는 구조체가 자신의 데이터를 스스로 제어하도록 보장하며, 외부 코드는 상호작용을 위해 제공된 메서드를 사용해야만 합니다.
직접 해보기
mod sensor;
use sensor::TemperatureSensor;
fn main() {
// 입력 읽기
let mut location = String::new();
std::io::stdin().read_line(&mut location).expect("Failed to read line");
let location = location.trim().to_string();
let mut reading_str = String::new();
std::io::stdin().read_line(&mut reading_str).expect("Failed to read line");
let reading: f64 = reading_str.trim().parse().expect("Failed to parse reading");
// TODO: 생성자를 사용하여 TemperatureSensor 생성
// new 함수가 확인 메시지 출력을 처리합니다
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.