아요 개발 일기

[Swift] Struct - 구조체 본문

Swift/Grammar

[Swift] Struct - 구조체

소진이 2023. 1. 27. 18:45

Struct

  • C 언어 구조체 용도와 비슷하지만, 추가로 멤버 변수(프로퍼티), 함수(메소드) 정의 가능
  • 상속이 불가능
  • 확장(extention) 등 기능 사용 가능
  • 값 타입 (= Value Type)
  • Swift의 대부분의 큰 뼈대는 모두 구조체로 구성
  • 메모리의 Stack 영역에 존재

값 타입이 뭐에요?

 

값 타입이란, 데이터의 크기가 고정적이기 때문에 메모리 스택에 생성되는 것을 말 합니다.

 

  • 선언 : 선언만 하면 스택에 즉시 생성되므로 선언 직후부터 데이터를 저장하는 용도로 사용할 수 있습니다.
  • 종료 : 더 이상 참조하는 변수가 없을 때 가비지 컬렉터에 의해 파괴됩니다.
  • 데이터 : 복사에 의해 완전한 별개의 사본이 생성 되며 복사 후 사본과 원본은 별개의 변수 입니다. 즉, 완전히 다른 두 개의 변수가 생성되는 것을 말 합니다.

Stack에 대해 자세히 알고 싶은 분들은 메모리 구조 (feat.Stack과 Heap)포스팅을 참고해주세요!


정의 및 구현

 

struct 선언 후 이름만 선언하면되는 쉬운 코드니 어려움은 없죠?

struct 구조체 이름 {
 ...
}

 

그냥 정의 부분만 보면 이해가 어려우니 구현 부분도 함께 보도록 하겠습니다!

 

struct Student {

    var name : String = "unknown"
    var `class`: String = "Swift"
    
    static func selfIntroduce() {
        print("학생타입입니다")
    }
    
    func selfIntroduce() {
        print("저는 \(self.class)반 \(name)입니다.")
    }
}

 

Student 구조체를 만들고 안에 객체와 함수들을 선언하였습니다.

 


근데 코드를 보면 변수명이 `class`인 부분이 눈에 띄죠??? 먼저 선언한 변수 name과 달리 ``로 묶여있는데 왜 일까요?

스위프트에서는 예약어나 키워드로 등록되어 있는 단어는 변수나 상수명에 사용할 수 없습니다. class는 저희가 클래스를 정의할때 사용하는 키워드죠???? 그럼 변수명으로 사용이 불가능합니다..

그치만! 아래 설명과 같이 사용하면 예약어나 키워드를 변수명으로 사용할 수 있습니다.

Class, Enum 등으로 예약어를 대소문자를 바꾸거나 ``로 묶으면 변수 명으로도 사용가능하죠! (근데 되도록이면 예약어나 키워드는 변수명으로 사용하지 않는게 좋아요)


 

인스턴스를 생성하여 구조체를 활용해볼까요?

struct Student {
    var name : String = "unknown"
    var `class`: String = "Swift"
    
    static func selfIntroduce() {
        print("학생타입입니다")
    }
    
    func selfIntroduce() {
        print("저는 \(self.class)반 \(name)입니다.")
    }
}


Student.selfIntroduce() //학생 타입 입니다.

var yegom: Student = Student()
yegom.name = "yegom"
yegom.class = "스위프트"
yegom.selfIntroduce() //저는 스위프트반 yegom입니다.


let jina:Student = Student()

//불변 인스턴스이므로 프로퍼티 값 변경 불가
//컴파일 오류 발생
//jin.name = "jina"
jina.selfIntroduce()//저는 Swift반 unknown입니다.

yegom 이름으로 Student 구조체를 선언하였습니다.

 

`class` 객체는 인스턴스를 이용하여 불러올때 ``없이 class라고만 선언하는 것을 볼 수 있습니다.

아래 let으로 선언한 jina 인스턴스는 당연히 불변이니까 값을 바꾸려고 하면 오류가 발생하겠죠?

 

 

다른 예시 코드도 함께볼까요?

 

struct MyData {
    var age:Int
    var name:String
    
    func getData() ->String {
        return "[\(name)(\(age))]"
        
    }
    
}

var data = MyData(age: 99, name: "Taro")
var data2 = data
data2.name = "Sojin"
data2.age = 24
print(data.getData()) // Taro(99)
print(data2.getData()) // Sojin(24)

 

 

위의 코드의 data 처럼 직접 변수 값들을 넣어주면서 인스턴스를 생성하는 것도 가능합니다.

 

구조체는 내부에서 데이터를 수정할때 꼭 사용해야하는 단어가 있는데요.

바로 Mutating func입니다. 아래 설명을 같이 볼까요?


Mutating function

Mutating function이란 구조체의 매서드가 구조체 내부에서 데이터를 수정할 때 선언하는 키워드입니다.

 

아래 코드를 보면서 이해해봅시다.

struct Point {
var x = 0 
var y = 0 

// 컴파일 에러남.
func moveTo(x: Int, y: Int) {
	self.x = x  
	self.y = y  
  }

// 정상 실행
mutating func moveTo2(x: Int, y: Int) {
	self.x = x  
	self.y = y  
  }
}

변수 x,y를 0으로 선언을 하였고, 그 값을 변경하려 합니다.

mutating을 선언하지 않고 내부 변수 값을 변경하면 위와 같이 컴파일 에러가 나게되니깐 꼭 붙여주세요!

 

음.. 구조체를 그럼 언제 사용해야하나요?

 


 

swift 언어 가이드에서 친절하게 아래 조건 중에 한가지 또는 그 이상 해당하는 경우에는 구조체를 사용하라고 기준을 제시해 주었습니다.

 

  • 서로 연관된 몇 개의 기본 데이터 타입들을 캡슐화하여 묶는 것이 목적일 때
  • 캡슐화된 데이터에 상속이 필요하지 않을 때
  • 캡슐화된 데이터를 전달하거나 할당하는 과정에서 참조 방식보다는 값이 복사되는 것이 합리적일 때
  • 캡슐화된 원본 데이터를 보존해야 할 때

 

Struct를 써야하는 경우

1. 두 object 를 “같다, 다르다”로 비교해야하는 경우

2. Copy된 각 객체들이 독립적인 상태를 가져야 하는 경우

3. 코드에서 오브젝트의 데이터를 여러 스레드 걸쳐 사용할 경우 (value 타입을 사용하면 각각의 객체이므로 오류 발상하지 않음)


 

'Swift > Grammar' 카테고리의 다른 글

[Swift] Enum - 열거형  (0) 2023.01.29
[Swift] 조건문 - Switch case  (0) 2023.01.29
[Swift] Class - 클래스  (0) 2023.01.27
[Swift] 고차 함수  (0) 2023.01.27
[Swift] 오류처리  (0) 2023.01.27