mutating

이원희·2021년 3월 11일
3

 🐧 Swift

목록 보기
30/32
post-thumbnail

드디어 mutating에 대해서 다룬다!
Swift struct, class에 대해 공부할때 mutating에 대해 많이 고민했다...
도대체 이게 뭔지 왜 이걸 붙여야 하는지!
이제는 정리할 때인거 같아서 포스팅한다.

mutating

오늘도 공식 문서를 먼저 봐보자.

structenum은 value type이다.
기본적으로 value type의 property들은 인스턴스 메서드에 의해 수정될 수 없다.
하지만, 특정 메서드 내에서 struct, enum의 property를 수정해야하는 경우 mutating을 통해 해결할 수 있다.

mutating을 선언한 메서드는 메서드 내에서 property를 변경할 수 있고, 메서드가 종료될 때 변경한 모든 내용을 원래 struct에 다시 기록한다.
메서드는 self property에 새 인스턴스를 할당할 수도 있다.

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")

Point struct에 Point 인스턴스를 이동하는 mutating func moveBy()를 정의했다.
새로운 Point를 반환하는 대신 실제로 호출 된 Point를 수정한다.

만약, let으로 선언된 인스턴스는 property가 변수여도 속성을 변경할 수 없기 때문에 mutating 메서드를 호출할 수 없다.

흠.. 정리를 해보자

  • struct, enumvalue type이다.
  • value type의 property들은 인스턴스 메서드에 의해 수정될 수 없지만 mutating은 이를 가능하게 해준다.

그렇다면 메서드가 종료될 때 변경한 모든 내용을 원래 struct에 다시 기록은 무슨 말일까?


value type copy

Swift Array Code를 살펴보면 아래와 같은 설명을 볼 수 있다.

Arrays, like all variable-size collections in the standard library, use copy-on-write optimization.
Multiple copies of an array share the same storage until you modify one of the copies.
When that happens, the array being modified replaces its storage with a uniquely owned copy of itself, which is then modified in place.
Optimizations are sometimes applied that can reduce the amount of copying.
This means that if an array is sharing storage with other copies, the first mutating operation on that array incurs the cost of copying the array.
An array that is the sole owner of its storage can perform mutating operations in place.
In the example below, a numbers array is created along with two copies that share the same storage.
When the original numbers array is modified, it makes a unique copy of its storage before making the modification.
Further modifications to numbers are made in place, while the two copies continue to share the original storage.

표준 라이브러리의 모든 가변 크기 collection과 마찬가지로 배열은 copy-on-write(COW) 최적화를 사용한다.
Array의 여러 복사본은 복사본 중 하나를 수정할 때까지 동일한 저장소를 공유한다.
수정되는 Array는 원본의 복사본으로 교체한 다음 제자리에서 수정된다.
복사량을 줄이기 위해 최적화가 적용되는 경우가 있다.

즉, Array가 다른 복사본과 저장소를 공유하는 경우 해당 Array의 첫번째 mutating으로 Array 복사가 발생한다.

var numbers = [1, 2, 3, 4, 5]
var firstCopy = numbers
var secondCopy = numbers

// The storage for 'numbers' is copied here
numbers[0] = 100
numbers[1] = 200
numbers[2] = 300
// 'numbers' is [100, 200, 300, 4, 5]
// 'firstCopy' and 'secondCopy' are [1, 2, 3, 4, 5]

위의 경우에서도 numbers, firstCopy, secondCopy가 처음에는 같은 저장소를 공유하고 있다.
numbers의 값이 바뀔 때, 저장소가 복사되고 numbers는 복사된 저장소를 가지고 있게 된다.

그렇다면 mutating이란?

위에서 살펴본 것처럼 Swift는 값이 변경될 때 복사를 하는 COW로 최적화를 진행한다.
structproperty 값이 변경될 때에는 Swift가 직관적으로 알 수 있다.
(이는 let, var 키워드를 통해 컴파일러가 이미 알고 있다.)
mutating 키워드 없이 메서드가 property를 변경하게 되면 언제 실제로 복사를 해야하는지 알 수가 없다.
따라서, mutating 키워드는 해당 메서드가 호출된다면 실제 복사를 해야한다고 알려주는 역할이다.


마무리

드디어 mutating에 대해서 정리했다.
처음에는 COW에 대해서 모르고 접근해서 이해하기 힘들었는데 알고 보니 넘나리 잘 이해된다.
그럼 이만👋

0개의 댓글