Menu
Coddy logo textTech

Setter

Coddy Rust 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 12번째.

게터(Getters)는 외부 코드에서 비공개 데이터를 읽을 수 있게 해줍니다. 하지만 외부에서 데이터를 변경하도록 허용해야 한다면 어떨까요? 바로 여기서 세터 메서드(setter methods)가 등장합니다. 이는 비공개 필드를 제어된 방식으로 수정하는 공개 메서드입니다.

기본적인 세터(setter)는 &mut self와 새로운 값을 인자로 받습니다:

// wallet.rs
pub struct Wallet {
    balance: f64,
}

impl Wallet {
    pub fn new(initial: f64) -> Wallet {
        Self { balance: initial }
    }
    
    pub fn balance(&self) -> f64 {
        self.balance
    }
    
    pub fn set_balance(&mut self, amount: f64) {
        self.balance = amount;
    }
}

getter와 달리, Rust의 setter는 일반적으로 데이터를 수정한다는 것을 명확하게 나타내기 위해 set_ 접두사를 사용합니다. &mut self 매개변수는 필수적입니다. 이는 메서드에 구조체의 필드를 변경할 수 있는 권한을 부여하기 때문입니다.

세터(setter)의 진정한 힘은 검증에 있습니다. 어떤 값이든 무분별하게 받아들이는 대신, 다음과 같이 규칙을 적용할 수 있습니다:

pub fn set_balance(&mut self, amount: f64) {
    if amount >= 0.0 {
        self.balance = amount;
    }
    // 음수 값은 자동으로 무시됩니다
}

이제 지갑은 스스로를 보호합니다. 외부 코드에서 어떤 값을 설정하려고 시도하더라도, balance는 결코 음수가 될 수 없습니다. 이것이 바로 캡슐화(encapsulation)가 실제로 작동하는 방식입니다. struct가 스스로의 불변성(invariants)을 제어하며, 외부 코드는 단순히 그것을 유효하지 않은 상태로 만들 수 없습니다.

challenge icon

챌린지

쉬움

데이터의 유효성을 유지하기 위해 세터(setter)가 어떻게 규칙을 강제할 수 있는지 보여주는 온도 조절기 시스템을 만들어 보겠습니다. 여러분의 온도 조절기에는 안전한 범위 내에서만 조정할 수 있는 온도 설정 기능이 있습니다.

코드를 정리하기 위해 두 개의 파일을 생성합니다:

  • thermostat.rs: 비공개(private) temperature 필드(i32)를 가진 Thermostat 구조체를 정의합니다. 구조체는 공개(public)되어야 하지만, 필드는 잘못된 값으로부터 보호하기 위해 비공개로 유지합니다. 다음을 구현하세요:
    • 초기 온도를 매개변수로 받는 new 생성자
    • 현재 온도를 반환하는 temperature 게터(getter)
    • 10에서 30 사이(포함)의 값만 허용하는 set_temperature 세터. 값이 이 범위를 벗어나면 온도는 변경되지 않고 그대로 유지되어야 합니다.
  • main.rs: 온도 조절기 모듈을 가져와서 온도 조절기 인스턴스를 생성하고, 다양한 온도로 설정을 시도한 후 매 시도마다 결과를 출력하여 세터의 유효성 검사를 시연합니다.

세터는 유효하지 않은 값을 조용히 무시해야 합니다. 즉, 에러 메시지를 출력하지 않고, 유효 범위를 벗어난 값으로 설정을 시도할 때 현재 온도를 변경하지 않고 그대로 유지합니다.

출력은 반드시 다음 형식을 따라야 합니다:

Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}

예를 들어, 온도를 20으로 설정하여 온도 조절기를 생성한 후, 25(유효)로 설정을 시도하고 이어서 50(유효하지 않음)으로 설정을 시도하면 출력은 다음과 같습니다:

Initial: 20
After setting to 25: 25
After setting to 50: 25

세 개의 입력을 받게 됩니다: 초기 온도, 첫 번째 시도할 온도, 그리고 두 번째 시도할 온도입니다.

치트 시트

Setter 메서드는 외부 코드에서 비공개 필드를 제어된 방식으로 수정할 수 있도록 합니다. 이 메서드들은 구조체의 데이터를 변경할 수 있는 권한을 얻기 위해 &mut self를 매개변수로 받습니다.

기본적인 setter 구문:

pub fn set_balance(&mut self, amount: f64) {
    self.balance = amount;
}

Rust의 setter는 일반적으로 데이터를 수정한다는 것을 명확히 나타내기 위해 set_ 접두사를 사용합니다.

Setter를 사용하면 규칙을 강제하고 데이터 무결성을 유지하기 위한 검증(validation)이 가능해집니다:

pub fn set_balance(&mut self, amount: f64) {
    if amount >= 0.0 {
        self.balance = amount;
    }
    // 유효하지 않은 값은 자동으로 무시됩니다.
}

이것이 바로 캡슐화의 실제 사례입니다. 구조체가 스스로의 불변성(invariants)을 제어하여, 외부 코드가 구조체를 유효하지 않은 상태로 만드는 것을 방지합니다.

직접 해보기

mod thermostat;

use thermostat::Thermostat;

fn main() {
    // 입력 읽기
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let initial_temp: i32 = input1.trim().parse().expect("Invalid number");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let first_attempt: i32 = input2.trim().parse().expect("Invalid number");

    let mut input3 = String::new();
    std::io::stdin().read_line(&mut input3).expect("Failed to read line");
    let second_attempt: i32 = input3.trim().parse().expect("Invalid number");

    // TODO: 초기 온도로 온도 조절기(thermostat) 생성

    // TODO: 초기 온도 출력
    // 형식: "Initial: {temperature}"

    // TODO: 첫 번째 온도 설정을 시도하고 결과 출력
    // 형식: "After setting to {attempted_value}: {temperature}"

    // TODO: 두 번째 온도 설정을 시도하고 결과 출력
    // 형식: "After setting to {attempted_value}: {temperature}"
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨