struct — 개념, 핵심 원리 및 Swift에서의 구문

저자: IT Sectr 게시일: 2026-06-17 읽는 시간: 7 분

Struct는 Swift 언어의 값 타입(value type)으로, 코드 부분 간에 전달될 때 인스턴스가 복사됩니다. 클래스와 달리 구조체는 상속을 지원하지 않지만 프로토콜을 구현하고, 속성과 메서드를 가지며, ARC 없이 예측 가능한 메모리 관리를 제공합니다. Swift Programming Language Guide, 2026에 따르면, struct는 Swift의 기본 구성 요소입니다. Int, String, Array, Dictionary와 같은 표준 타입조차 구조체로 구현되어 있습니다. Swift 언어는 데이터 모델링을 위해 구조체를 우선 선택으로 권장합니다.

핵심 포인트

  • Struct는 Swift의 값 타입으로, 할당 시 복사되며 참조가 아닌 값으로 전달됩니다.
  • Copy-on-Write는 실제 데이터 복사가 할당 시가 아니라 값이 수정될 때만 발생하는 최적화입니다.
  • Mutating은 구조체의 속성을 변경하는 메서드에 필요한 키워드입니다.
  • 프로토콜 — 구조체는 프로토콜과 확장을 구현할 수 있어 상속 없이 유연성을 제공합니다.
  • 안전성 — 참조 사이클이 없어 멀티스레드 코드와 데이터 모델에 구조체가 적합합니다.

Swift에서 struct란?

Struct(구조체)는 관련 속성과 메서드를 단일 엔터티로 그룹화하는 Swift의 복합 데이터 타입입니다. 클래스와 달리 구조체는 값 타입입니다. 함수에 전달하거나 새 변수에 할당하면 원본 객체에 대한 참조가 아닌 구조체의 독립적인 복사본이 생성됩니다.

Swift는 모든 기본 타입에 구조체를 사용합니다: Int, Double, String, Bool, Array, Dictionary, Set. 즉, 기본적인 Int조차 구조체처럼 동작하여 할당 시 복사본이 생성됩니다. 개발자는 원하는 속성과 메서드 집합으로 자신만의 구조체를 정의할 수 있습니다.

Swift Evolution (SE-0143)에 따르면, 표준 타입을 구조체로 구현하기로 한 결정은 성능과 예측 가능성 때문입니다. 값 타입은 참조 사이클을 만들지 않으며, ARC 참조 카운팅이 필요 없고, 복사본의 수정이 원본에 영향을 미치지 않음을 보장합니다. 이는 멀티스레드 시나리오에서 데이터 불변성에 매우 중요합니다.

값 타입으로서의 struct

값 타입 의미론이 struct와 class의 주요 차이점입니다. 구조체를 새 변수에 할당하거나 함수에 전달하면 Swift는 모든 데이터의 독립적인 복사본을 만듭니다. 복사본에 대한 변경 사항은 원본에 영향을 미치지 않아 참조 타입의 일반적인 부작용을 제거합니다.

swift
// 값 타입 의미론의 예
struct Point {
    var x: Double
    var y: Double
}

var p1 = Point(x: 10, y: 20)
var p2 = p1        // p2는 p1의 독립적인 복사본
p2.x = 99            // p2만 변경됨
print(p1.x)         // 10 — p1 변경되지 않음
print(p2.x)         // 99

Copy-on-Write 최적화

Swift는 복사 최적화를 위해 Copy-on-Write(COW)를 사용합니다. 여러 변수가 동일한 구조체를 참조하지만 그중 어느 것도 데이터를 수정하지 않으면 실제 복사가 발생하지 않습니다. Swift는 첫 번째 변경까지 변수 간에 메모리를 공유하다가 그때 실제 복사본을 만듭니다. 이는 과도한 할당 작업을 방지하고 컬렉션 작업 속도를 높입니다.

가변성과 mutating 메서드

기본적으로 구조체의 메서드는 해당 속성을 변경할 수 없습니다. Swift는 변경을 수행하는 메서드에 명시적 mutating 키워드를 요구합니다. 이 제한은 우발적인 변경을 방지하고 코드를 예측 가능하게 만듭니다. 메서드가 mutating으로 표시되지 않으면 구조체를 변경하지 않음이 보장됩니다.

Mutating의 작동

메서드 앞에 mutating 키워드를 추가하면 Swift는 구조체의 속성에 새 값을 쓸 수 있습니다. 실제로 메서드는 self = 를 통해 구조체 인스턴스를 완전히 새로운 것으로 바꿀 수도 있습니다. 이 메커니즘은 예를 들어 Option 및 Result 타입에서 사용됩니다.

swift
// Mutating 메서드가 있는 struct
struct Counter {
    private var value: Int = 0

    // Mutating 메서드 — 속성을 수정할 수 있음
    mutating func increment() {
        value += 1
    }

    // Mutating 메서드는 self를 완전히 대체할 수 있음
    mutating func reset() {
        self = Counter()
    }

    // 비-mutating 메서드 — 읽기 전용
    func currentValue() -> Int {
        return value
    }
}

var counter = Counter()
counter.increment()
print(counter.currentValue())  // 1
counter.reset()
print(counter.currentValue())  // 0

Mutating 규칙: 구조체는 var로 선언해야 하며 let으로 선언할 수 없습니다. 상수 구조체는 mutating 메서드를 호출할 수 없습니다. 컴파일러는 빌드 시 이를 확인하며, let 상수에서 mutating 메서드를 호출하려고 하면 컴파일 오류가 발생합니다.

Struct vs Class: 비교

struct와 class 중 선택은 Swift에서 근본적인 결정 중 하나입니다. 두 타입 모두 속성, 메서드, 초기화자를 가질 수 있고 프로토콜을 구현할 수 있지만, 메모리 의미론, 상속, 라이프사이클 관리에서 근본적인 차이가 있습니다.

특성structclass
타입값 타입(복사됨)참조 타입(참조)
상속지원하지 않음지원함
ARC / 참조 카운팅필요 없음ARC 필요
초기화 해제지원하지 않음deinit 지원
상수에서 속성 변경var로만 가능let으로 가능(참조는 상수)
타입 캐스팅지원하지 않음지원함
컬렉션 저장직접 저장(값)참조로 저장(포인터)

구조체는 데이터가 상속이 필요하지 않음, 공유 ID를 가지면 안 되는 경우(예: 좌표, 크기, 구성) 및 모듈 간에 전달될 때 선호됩니다. 클래스는 UI 구성 요소(UIView, UIViewController), 싱글톤 및 공유 ID가 있는 객체에 선택됩니다.

struct를 선택해야 하는 경우

Apple은 Swift에서 데이터 모델링을 위해 struct를 기본 타입으로 사용할 것을 권장합니다. 구조체는 예측 가능한 복사 의미론과 참조 카운팅 오버헤드가 없어 대부분의 시나리오에 적합합니다. struct가 최적의 선택인 일반적인 경우를 살펴보겠습니다.

상속이 없는 데이터 모델

엔터티가 상속 없이 데이터를 포함하는 경우(Product, User, Order, Point) struct를 사용하세요. 컴파일러가 자동으로 memberwise initializer를 생성하므로 init을 수동으로 작성할 필요가 없습니다. Equatable과 Hashable도 모든 속성이 이러한 프로토콜을 준수하는 구조체에 대해 자동으로 구현됩니다.

불변 데이터

생성 후 변경되지 않는 구성, 설정 및 플래그의 경우 class보다 struct가 더 좋습니다. 상수(let) 구조체는 모든 중첩 필드의 불변성을 보장하지만, class에서는 이것이 참조에만 적용되고 객체 내용에는 적용되지 않습니다.

멀티스레드 코드

값 의미론으로 인해 구조체는 멀티스레드 환경에서 안전합니다. 각 스레드는 데이터의 독립적인 복사본을 가져와 다른 스레드에 영향을 주지 않습니다. 값 타입에서는 스레드 간 데이터 경합이 불가능하므로 SwiftUI의 모델에 struct가 선호됩니다(ObservableObject는 class가 필요하지만 @State는 struct를 사용함).

swift
// 데이터 모델을 위한 struct 사용 예
struct User: Codable, Identifiable {
    let id: UUID
    var name: String
    var email: String
    var isPremium: Bool

    // 계산 속성 — non-mutating
    var displayName: String {
        isPremium ? "\(name) ⭐️" : name
    }
}

// 자동 memberwise 초기화자
let user = User(
    id: UUID(),
    name: "Alice",
    email: "alice@example.com",
    isPremium: true
)

// 멀티스레딩에 안전한 복사
var userCopy = user
userCopy.isPremium = false
// user.isPremium은 true를 유지

상속(UIKit/AppKit 구성 요소), 공유 ID(대리자, 관찰자) 또는 제어된 객체 라이프사이클(deinit)이 필요한 경우 class를 사용하세요. 그 외 모든 경우에는 struct를 사용하세요.

자주 묻는 질문

Swift에서 struct란?

Struct는 Swift의 값 타입으로, 코드 부분 간에 전달될 때 복사됩니다. 구조체는 속성, 메서드, 초기화자를 가질 수 있으며 프로토콜을 구현할 수 있습니다. Swift의 기본 타입(Int, String, Array)은 구조체로 구현되어 있습니다.

Swift에서 struct와 class의 차이점은?

Struct는 값 타입(할당 시 복사), 상속을 지원하지 않으며 ARC 불필요. Class는 참조 타입(참조로 전달), 상속, 초기화 해제 및 참조 카운팅을 지원. 개발자는 struct를 기본 타입으로 권장합니다.

Swift struct에서 mutating이란?

Mutating은 구조체 메서드가 해당 속성을 변경할 수 있음을 나타내는 키워드입니다. mutating 없이 컴파일러는 필드 수정을 금지합니다. mutating 메서드는 var로 선언된 변수에서만 호출할 수 있으며 let에서는 호출할 수 없습니다.

Swift에서 Copy-on-Write란?

Copy-on-Write(COW)는 구조체에 대한 Swift 최적화로, 실제 데이터 복사가 첫 번째 변경까지 지연됩니다. 모든 변수가 구조체를 읽기만 하는 동안 하나의 메모리 영역을 공유합니다. 큰 컬렉션 작업 시 성능이 향상됩니다.

Swift에서 struct와 class는 각각 언제 사용하나요?

상속 없는 데이터 모델, 구성, DTO 및 멀티스레드 시나리오에는 struct를 사용하세요. UIKit/AppKit UI 구성 요소, 싱글톤, 공유 ID가 있는 엔터티(대리자, 관찰자) 및 초기화 해제가 필요한 객체에는 class를 사용하세요.

요약

  • Struct는 Swift의 값 타입으로, 할당 시 복사되며 복사본 간 부작용 없는 예측 가능한 동작을 제공합니다.
  • Copy-on-Write는 구조체 성능을 최적화하며 실제 복사는 모든 할당이 아닌 첫 번째 변경 시에만 발생합니다.
  • Swift 표준 타입 — Int, String, Array, Dictionary — 은 구조체로 구현되어 모든 기본 작업에 값 의미론을 보장합니다.
  • Mutating은 구조체 속성을 변경하는 메서드에 필수적인 키워드이며 var 인스턴스에서만 호출할 수 있습니다.
  • 구조체는 상속을 지원하지 않지만 프로토콜을 구현하고 기능 추가를 위해 확장을 사용할 수 있습니다.
  • Equatable 및 Hashable은 모든 속성이 이러한 프로토콜을 준수하는 구조체에 대해 자동으로 구현되어 비교 및 컬렉션 사용이 간편해집니다.
  • Apple은 struct를 기본 타입으로 권장하며, class는 상속, 공유 ID 또는 제어된 객체 라이프사이클이 필요한 경우에만 사용하세요.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기