💥 Generic(제네릭)
- 타입에 의존하지 않는 범용 코드를 작성할 때 사용된다.
🌟 제네릭 함수
- 만약 내가 인자로 들어오는 int값을 서로 swap하는 함수를 만든다고 가정해보자. 그러면 아래와 같이 함수 코드를 작성할 있다.
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let tempA = a
a = b
b = tempA
}
- 그리고, 만약 내가 String값을 서로 swap하는 함수를 만든다고 가정을 한다면?
func swapTwoStrings(_ a: inout String, _ b: inout String) {
let tempA = a
a = b
b = tempA
}
- 즉, 위와 같이 type 별로 같은 기능을 하는 함수를 만들어줘야된다.
- 그러나, 아래와 같이 제네릭 함수를 사용하면 타입에 상관없이 하나의 함수만을 사용하여 기능을 구현할 수 있다.
T
⇒ Type Parameter라고 부른다.
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let tempA = a
a = b
b = tempA
}
🌟 제네릭 타입
- 제네릭 함수뿐만 아니라, 제네릭을 사용하여 타입을 생성해 줄 수도 있다.
- 제네릭을 활용하여 stack을 만들어보자.
struct Stack<T> {
let data: [T] = []
mutating func push(_ data: T) {
... }
mutating func pop() -> T {
... }
}
- 그리고 제네릭 타입의 인스턴스를 생성해주기 위해서는 <>을 통하여 타입을 명시해주어야된다.
let intStack: Stack<Int> = .init()
or
let intStack = Stack<Int>.init()
- 그런데, 위와 같은 형식은 우리가 평소에 array를 만들때 사용하는 방식과 똑같다.
- 왜냐하면, array도 generic이거든!
let intArray: Array<Int> = .init()
or
let intArray = Array<Int>.init()
🌟 타입 제약주기
- 제네릭 함수 및 타입을 사용할 때에 특정한 클래스만 혹은 프로토콜을 준수하는 타입만 받을 수 있게 제약을 줄 수 있다.
🫧 프로토콜 제약
- Type Parameter 옆에 프로토콜을 추가하여, 해당 프로토콜을 만족하는 파라미터만 받을 수 있게 설정할 수 있다.
func isSameValues<T: Equatable>(_ a: T, _ b: T) -> Bool {
return a == b
}
🫧 클래스 제약
- Type Parameter 옆에 클래스를 추가하여, 해당 클래스 혹은 해당 클래스의 하위 클래만 파라미터만 받을 수 있게 설정할 수 있다.
- 아래의 예는, Human class 혹은 Human class의 하위 클래스만 파라미터로 받을 수 있다.
func function<T: Human>(_ a: T) { }
📚 참고자료
Swift) 제네릭(Generic) 정복하기