본문 바로가기
카테고리 없음

17. 제네릭(Generic)의 기본 개념과 활용

by swifttt 2025. 4. 6.

 

 

Swift에서 제네릭(Generic)은 유연하면서도 재사용 가능한 코드를 작성할 수 있게 해주는 기능입니다.
함수, 구조체, 클래스, 열거형 등에서 다양한 타입을 다루어야 할 때, 코드 중복 없이 하나의 틀로 작성할 수 있도록 도와줍니다.

제네릭은 타입 안정성과 성능을 모두 보장하면서도, 추상적이고 확장 가능한 코드를 작성하는 데 매우 유용한 도구입니다.

1. 제네릭 함수의 기본

가장 간단한 형태의 제네릭 함수는 아래와 같이 정의합니다.

func swapValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

이 함수는 두 값을 받아 서로 바꾸는 함수입니다.
타입 매개변수 T는 어떤 타입이든 받아들일 수 있으며, 두 값의 타입은 같아야 합니다.

사용 예시는 다음과 같습니다.

var x = 10
var y = 20
swapValues(&x, &y)
print(x, y) // 20 10

var str1 = "Hello"
var str2 = "World"
swapValues(&str1, &str2)
print(str1, str2) // World Hello

하나의 함수로 Int, String 등 다양한 타입의 값을 처리할 수 있습니다.

2. 제네릭 타입

제네릭은 구조체, 클래스, 열거형에서도 사용할 수 있습니다.

struct Stack<Element> {
    private var items: [Element] = []

    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -> Element? {
        return items.popLast()
    }
}

Stack 구조체는 Element라는 제네릭 타입을 이용하여 어떤 타입의 요소든 쌓을 수 있도록 설계되었습니다.

var intStack = Stack<Int>()
intStack.push(3)
intStack.push(7)
print(intStack.pop()!) // 7

var stringStack = Stack<String>()
stringStack.push("Swift")
stringStack.push("Generic")
print(stringStack.pop()!) // Generic

3. 타입 제약(Type Constraints)

제네릭 타입 매개변수는 특정 조건을 만족하도록 제한할 수 있습니다.
예를 들어, Equatable을 따르는 타입만 받을 수 있도록 제한할 수 있습니다.

func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int? {
    for (index, element) in array.enumerated() {
        if element == value {
            return index
        }
    }
    return nil
}

let animals = ["Cat", "Dog", "Bird"]
if let index = findIndex(of: "Dog", in: animals) {
    print("Dog의 위치는 \(index)입니다.") // Dog의 위치는 1입니다.
}

T: EquatableTEquatable 프로토콜을 따르는 타입임을 의미합니다.

4. 여러 타입 매개변수 사용

하나 이상의 제네릭 매개변수를 동시에 사용할 수도 있습니다.

struct Pair<A, B> {
    var first: A
    var second: B
}

let pair = Pair(first: "Hello", second: 123)

Pair는 서로 다른 두 타입을 하나의 구조체로 묶는 데 유용합니다.

마무리

제네릭은 Swift의 강력한 타입 시스템을 기반으로, 다양한 타입에 대해 하나의 추상화된 코드로 처리할 수 있는 기능입니다.
제네릭을 사용하면 코드의 중복을 줄이면서도 타입 안정성을 확보할 수 있고, 더 넓은 범위에서 재사용 가능한 함수나 타입을 만들 수 있습니다.
특히 라이브러리나 공통 유틸리티를 설계할 때 제네릭은 필수적인 기능입니다.