GGURUPiOS

[Swift] Struct와 Mutating 키워드(구조체에 대한 고찰) 본문

Swift/문법 파헤치기

[Swift] Struct와 Mutating 키워드(구조체에 대한 고찰)

꾸럽 2023. 11. 2. 17:34

안녕하세요.

이번시간에는 수도없이 만나는 Structures에 대해 이야기해보고자 합니다

Structures가 무엇인지 알아보고, 또 Class와의 차이까지 알아보도록 할게요


struct? structures?

struct라는 키워드를 통해 구조체를 정의하고, 프로퍼티나 메서드를 정의할 수 있습니다.

 

struct someStructName {
	// 프로퍼티, 메서드 등등
}

 

구조체는 값 타입으로 변수나 상수에 할당될 때 또는 함수를 통해서 전달될 때 그 값을 복사합니다.

 

어떻게 쓸까요?

일단 구조체를 정의했다면 그 자체로는 메모리에 할당되지 않습니다.

우리는 구조체 인스턴스를 만들어야 사용할 수 있습니다.

 

 

아래와 같이 생성해서 사용 가능합니다.

struct Student {
    let name: String
    var age: Int
}

let student1 = Student(name: "민수", age: 26)

 

그런데 클래스와는 달리 Initializers를 지정하지 않았습니다. 그런데 어떻게 인스턴스 생성이 되는걸까요?

그 답은 바로 구조체는 자동으로 memberwise initializer를 제공하기 때문입니다.

 

물론 이니셜라이저를 직접 지정해도 됩니다.

클래스와 마찬가지로 이니셜라이저에서는 모든 프로퍼티의 초기화가 진행되어야 합니다.

 

Mutating

만약 구조체 내에서 메서드로 age 값을 바꾸고 싶다면 어떻게 해야할까요?

 

mutating 키워드를 사용하여 메서드를 정의하면 됩니다.

 

struct Student {
    let name: String
    var age: Int

    mutating func changeAge(age: Int) {
    	self.age = age
    }
}

var student1 = Student(name: "민수", age: 26)
student1.changeAge(age: 27)

student1.age = 28 // 가능

 

여기서 궁금증이 생겼습니다.

 

사실 아래의 궁금증 때문에 작성한 글이기도 합니다.

Why? Mutating?

사실 구조체 인스턴스를 만들고 난뒤에, 직접 접근해서 student1.age 에 28을 할당하면 정상적으로 동작합니다.

굳이 왜 클래스와 다르게 mutating이라는 키워드를 써야만 할까요?

(찾는데 정보가 잘 안나왔다.. 오래걸림)

 

스택오버플로우에 나랑 거의 똑같은 의문을 가진분이 질문한 글이 있어서 읽어봤다 (9년전..)

글에 따르면, 일단 스위프트 랭귀지 가이드에 보면 아래와 같은 글이 있다고 함

 

By default, the properties of a value type cannot be modified from within its instance methods. 

기본적으로, 값 타입은 인스턴스 메서드에서 프로퍼티값을 변경 못한다는 것이다.

 

해당 글을 읽어보니 결국 핵심은 이것이다.(이해한대로 작성, 틀렸을 수 있음)

 

mutability attribute (가변/불변)은 타입이 아니라 상수 또는 변수에 표시되는 것임

글에서는 가변/불변 모드가 있다고 한다.

 

즉, 구조체를 변수에 할당하면 값의 상태를 변경할 수 있는 가변 모드가 됨.

 

그렇다면 돌고돌아 왜 Mutating을 써야하는가?

 

구조체에는 일반메서드와 Mutating메서드 두가지가 있다.

일반 메서드는 불변의 의미를 지원하기 위해서만 존재한다

(불변 모드는 내부 프로퍼티의 값이 변하면 안되므로 일반 메서드 안에서는 내부 프로퍼티의 값을 변경할 수 없는것으로 이해)

 

=> 의미적 불변성을 보장해야 하므로

 

이렇게 의미적인 불변성을 보장하면 뭐가 좋을까요? 헷갈리기만 하는데

그 답은 mutating 값이 어떻게 변할지 예측하기 어렵고, 이것이 버그의 주요 원인 중 하나가 될 수 있기 때문이라고 합니다

 

또한, 불변 값은 최적화에 매우 유리하다고 한다.

 

그럼 클래스의 경우에는 어떨까요?

클래스에는 불변/가변 모드가 없다고 합니다. 왜냐하면 클래스는 일반적으로 참조가능 엔티티를 표하는 데 사용되기 때문

참조가능 엔티티는 보통 변경 가능인데, 적절한 성능으로 엔티티의 참조 그래프를 변경 불가능한 방식으로 만들고 관리하는것이 매우 어렵다고 함.

 

그래서 아래와 같이 이런 코드가 클래스에서는 되고 구조체에서는 안되고 하는 것 같습니다.

struct Student {
    let name: String
    var age: Int
    
    mutating func changeAge(_ age: Int) {
        self.age = age
    }
}

class School {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}


let school = School(name: "스위프트학교")
school.name = "스유스쿨" // let으로 선언했어도 무조건 가변한 클래스이기 때문에 내부 프로퍼티 수정가능

let student = Student(name: "민수", age: 26)
student.age = 24 // let으로 선언했기 때문에 불변 모드가 되어 내부 프로퍼티 수정 불가능

// 물론 school 에 새로운 인스턴스를 넣는것과 student 에 새로운 인스턴스를 할당하는것은 안된다.

 

그렇다면 student.changeAge(5)는 가능할까요?

역시 불가능합니다. let으로 선언된 순간 불변모드인것을 의미하기 때문에, 아무리 mutating 메서드로 접근을 해도 불가능 합니다.

 


 

의식의 흐름대로 작성된 것 같네요..

조금 이해가 안가던 부분이였지만 그래도 새로운 사실을 알게되어 좋았습니다.

 


 

출처

 

https://stackoverflow.com/questions/24035648/swift-and-mutating-struct

 

Swift and mutating struct

There is something that I don't entirely understand when it comes to mutating value types in Swift. As the "The Swift Programming Language" iBook states: By default, the properties of a value type

stackoverflow.com

 

 

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/classesandstructures/

 

Documentation

 

docs.swift.org