# 불변성과 가변성

Rust에서는 변수를 선언할 때 기본적으로 불변성(immutable)이 적용된다. 즉, `let` 키워드를 사용하여 변수를 선언하면, 그 값은 변경할 수 없도록 고정된다. 이는 Rust가 안전성과 예측 가능성을 확보하기 위해 제공하는 강력한 장치 중 하나다. 한 번 값이 정해지면 프로그램 어디에서도 임의로 변경되지 않으므로, 해당 값을 참조하고 활용하는 모든 코드는 동일한 결과를 얻게 된다. 이를 통해 프로그램의 동작을 파악하고 유지보수하기가 훨씬 쉬워진다.

불변 변수를 선언하는 예시를 살펴보면 다음과 같다.

```
let x = 10;
println!("x는 {}", x);
```

위 코드에서 `x`는 10으로 값을 초기화한 후 변경할 수 없게 된다. 만약 이후에 `x`에 새로운 값을 할당하려고 시도하면 컴파일 에러가 발생한다. 따라서 Rust 코드에서 가장 먼저 확인해야 할 기본 원칙은 "변수는 가능하면 불변으로 선언하는 것"이다. 이렇게 하면 코드가 복잡해지거나 의도치 않은 곳에서 값이 변동되는 일을 크게 줄일 수 있다.

다만 불변 변수만으로는 모든 기능을 구현하기 어렵다. 때로는 변수의 값을 변경해야 하는 상황이 분명히 존재한다. 이때 사용하는 키워드가 `mut`이다. `let mut` 키워드를 통해 변수를 선언하면, 해당 변수는 변경 가능한 상태를 갖게 된다. 예시는 다음과 같다.

```
let mut y = 20;
println!("초기 y는 {}", y);

y = 30;
println!("변경된 y는 {}", y);
```

여기서 `y`는 처음 20으로 값을 설정했다가 이후 30으로 변경된다. `mut` 키워드 덕분에 가능해진 동작이다. 그러나 가변성은 신중하게 사용해야 한다. 값이 여러 곳에서 동시에 변경될 가능성이 커질수록 예기치 못한 버그가 발생하기 쉽기 때문이다. Rust가 디폴트로 불변성을 채택한 이유는 변수 변경을 최소화하여 프로그램의 동작을 예측하기 쉽게 하려는 목적이 크다.

불변성과 가변성을 보다 깊이 이해하기 위해서는 빌림(borrowing)과 참조(reference)에 대한 개념도 함께 살펴봐야 한다. Rust에서는 참조를 나타낼 때 `&T` 형태로 표현하며, 이 역시 기본적으로 불변 참조이다. 불변 참조는 포인터처럼 동작하지만 값을 변경할 수 없는 한계가 명시된다. 반면 `&mut T` 형태의 참조는 가변 참조로서, 참조 대상을 변경할 수 있다. 단, Rust의 소유권(ownership) 규칙에 따라 가변 참조는 동시에 단 하나만 존재할 수 있으며, 이는 데이터 레이스(data race)를 방지하기 위한 안전장치로 작동한다.

불변 참조가 여러 개 존재하는 상황에서는 해당 데이터를 변경할 수 없다. 누구든지 값을 바꾸지 않는다는 사실이 확실하기 때문에, 여러 스레드나 여러 부분에서 동시에 읽어도 안전하다. 가변 참조를 사용할 때는 그 변수에 대한 다른 참조가 이미 존재하지 않아야 한다. 즉, Rust는 불변 참조들은 동시에 여러 개가 허용되지만, 가변 참조는 오직 단 하나만 허용하는 엄격한 규칙을 적용한다. 이 규칙을 위반하려 하면 컴파일 단계에서 에러가 발생하므로, 개발자는 동시성 관련 버그를 사전에 방지할 수 있다.

불변성의 또 다른 측면은 섀도잉(shadowing)이라는 기능에서도 확인할 수 있다. Rust에서는 동일한 이름의 변수를 재선언하여 새로운 스코프에서 새로운 값을 대입할 수 있다. 이는 원본 변수를 변경하지 않고도, 마치 새로운 변수를 만들어 기존 이름을 "덮어쓰는" 것처럼 동작한다. 예시는 아래와 같다.

```
let x = 5;
let x = x + 1;
{
    let x = x * 2;
    println!("스코프 내부의 x: {}", x);
}
println!("스코프 밖의 x: {}", x);
```

이 코드에서 `x`는 두 번 재선언되고, 내부 블록에서도 추가로 재선언된다. 각 스코프에서 `x`는 서로 다른 변수로 취급되며, 내부 스코프에서의 변화는 외부 스코프로 전파되지 않는다. 이처럼 Rust의 섀도잉은 불변 변수를 여러 번 선언하면서도, 기존 변수를 직접 수정하지 않는 방식을 가능하게 해준다.

불변성과 가변성은 Rust가 추구하는 안전성과 직결된 중요한 개념이다. 불변으로 선언하면 값이 달라지지 않는다는 점에서 프로그램의 동작을 추론하기 훨씬 편해지고, 가변성은 필요한 경우에만 명시적으로 열어두도록 설계되었다. 이러한 설계 방식은 규모가 큰 프로젝트나 멀티스레드 환경에서 특히 강력한 장점을 제공한다. 값이 예측 불가능하게 바뀌지 않고, 여러 스레드가 같은 데이터를 참조할 때 데이터 레이스를 일으키지 않는다.

결론적으로 Rust에서 불변성은 안전하고 예측 가능한 코드를 만드는 데 중요한 역할을 한다. 가능하면 불변 변수로 선언하고, 꼭 필요한 곳에서만 `mut`를 사용하여 변경 가능성을 허용하는 것이 바람직한 코딩 습관이다. 이를 통해 Rust의 엄격하지만 강력한 타입 검사와 소유권 모델을 최대한 활용하여 오류를 사전에 줄이고, 유지보수와 확장성 면에서 유리한 코드를 작성할 수 있다.
