쉬운 설명
`struct`는 하나의 완성된 상자라고 보면 된다. 상자 안의 물건 하나를 바꾸는 것도 결국 그 상자를 바꾸는 일이다. 그래서 Swift는 “이 메서드는 상자 내용을 바꿉니다”라고 `mutating`으로 표시하게 만든다.
값 타입에서 메서드가 내부 상태를 바꾸려면 왜 `mutating`을 붙여야 하는지, 결국 `self`를 수정하는 행위라는 점까지 연결해서 정리한 문서다.
2026-04-09 2026-04-14
`struct`는 하나의 완성된 상자라고 보면 된다. 상자 안의 물건 하나를 바꾸는 것도 결국 그 상자를 바꾸는 일이다. 그래서 Swift는 “이 메서드는 상자 내용을 바꿉니다”라고 `mutating`으로 표시하게 만든다.
`count += 1` 정도는 가볍게 보이지만, 값 타입에서는 그 자체가 `self` 변경이다. 이 규칙을 모르고 보면 왜 `mutating`이 필요한지, 왜 `let struct`에서 호출이 안 되는지 계속 헷갈리게 된다.
`struct`는 값 타입이라 변수 안에 값 전체가 들어 있다. 따라서 메서드 안에서 프로퍼티 하나를 바꾸는 것도 결국 그 값 전체를 바꾸는 행위로 본다. Swift는 이 의도를 숨기지 않도록 `mutating` 키워드를 붙여서 “이 메서드는 self를 바꾼다”고 명시하게 만든다.
struct Counter {
var count = 0
mutating func increment() {
count += 1
}
}`mutating`은 단순히 프로퍼티 하나를 바꾼다는 뜻이 아니라, 값 타입의 `self`를 수정한다는 선언이다.
맞다. `var`로 만든 `struct`는 내부 `var` 프로퍼티를 바꿀 수 있고, 그 변경을 메서드 안에서 하려면 `mutating`이 필요하다. 반대로 `let`으로 만든 `struct`는 값 전체가 상수이므로 `mutating` 메서드도 호출할 수 없다.
`let`으로 선언된 값 타입은 값 전체가 상수다. 그래서 `mutating` 메서드는 결국 상수인 `self`를 바꾸려는 시도가 되어 호출할 수 없다.
let counter = Counter()
// counter.increment() // 불가`class`는 참조 타입이라 메서드 안에서 보통 객체 내부 상태를 바꿔도 변수에 담긴 참조 자체를 바꾸는 것은 아니다. 그래서 값 타입처럼 `self` 수정 여부를 `mutating`으로 구분할 필요가 없다.
struct Counter {
var value: Int
mutating func increment() {
value += 1
}
}
var counter = Counter(value: 0)
counter.increment()struct Counter {
let value: Int
func updatingIncrement() -> Counter {
Counter(value: value + 1)
}
}
let counter = Counter(value: 0)
let nextCounter = counter.updatingIncrement()이 방식은 기존 값을 그대로 두고, 변경된 새 값을 만든다. 불변 스타일을 선호하는 상태 관리 코드에서 특히 읽기 좋다.
프로퍼티 하나만 바꾸는데 왜 `self`를 수정한다고 하나요?
값 타입에서는 프로퍼티 하나가 따로 떠 있는 것이 아니라 값 전체 안에 포함되어 있다. 그래서 프로퍼티 변경은 결국 그 값 전체를 바꾸는 것으로 본다.
`mutating`이 없으면 컴파일러는 무엇을 막는 건가요?
값 타입 메서드가 암묵적으로 상태를 바꾸는 것을 막는다. 즉 “이 메서드는 읽기 전용처럼 보이는데 실제로는 self를 바꾼다”는 혼란을 줄이기 위한 장치다.
`mutating` 대신 항상 새 값을 반환하면 안 되나요?
가능하다. 실제로 불변 스타일을 선호하면 `updating()`처럼 새 값을 반환하는 방식이 더 명확할 수 있다. 다만 상태 변경 메서드가 더 자연스러운 경우에는 `mutating`이 실용적이다.
이 개념이 왜 중요한가요?
값 타입의 상태 변경이 결국 `self` 수정이라는 점을 이해하면, `let`/`var`, 값 타입 선택, 불변 설계, 동시성 안전성까지 한 흐름으로 이해할 수 있다.
왜 프로퍼티 하나만 바꾸는 것도 `self` 변경으로 보나요?
값 타입에서는 프로퍼티가 객체 바깥 어딘가에 따로 존재하는 것이 아니라 값 전체 안에 포함된다. 그래서 `count += 1`은 `count`만 독립적으로 바꾸는 것이 아니라 그 값을 이루는 일부를 바꾸는 것이고, 결과적으로는 `self` 전체가 바뀌는 것으로 본다.
`mutating` 메서드는 내부적으로 `self = ...`와 비슷한가요?
개념적으로는 비슷하게 이해해도 된다. 실제로 `mutating` 메서드 안에서는 프로퍼티를 바꾸는 것뿐 아니라 `self` 전체를 다른 값으로 다시 넣는 것도 가능하다.
struct Point {
var x: Int
var y: Int
mutating func reset() {
self = Point(x: 0, y: 0)
}
}그럼 `mutating`은 값 타입에서만 필요한가요?
그렇다. `class`는 참조 타입이라 메서드 안에서 내부 프로퍼티를 바꿔도 참조 변수 자체를 다시 쓰는 것이 아니다. 그래서 값 타입처럼 “self 변경 여부”를 `mutating`으로 따로 표시하지 않는다.
`mutating` 대신 새 값을 반환하는 방식과 언제 구분하나요?
기존 인스턴스를 자연스럽게 업데이트하는 모델이면 `mutating`이 읽기 쉽다. 반대로 불변성을 더 강하게 유지하고 싶거나, 상태 흐름을 명확히 추적하고 싶다면 새 값을 반환하는 방식이 더 좋다. 상태 관리, 동시성, 테스트 관점에서는 새 값을 반환하는 패턴이 더 안전하게 느껴질 때가 많다.