728x90
|
제네릭 (Generics)
- 함수, 클래스 내부에서 사용할 타입 파라미터를 받아 어떤 타입에도 유연하게 대응하게 작성할 수 있는 스위프트 문법
1. 제네릭 함수
- 함수명 뒤에 '<플레이스홀더>' 와 같은 방식으로 선언이 가능하다.
- 이 때 플레이스 홀더의 타입은 전달되는 전달 인자에 의해 결정된다.
- 전달인자의 타입에 따라서 불필요한 추가 함수들을 만들 필요가 없다.
import UIKit
func swap<T>(a: inout T, b: inout T) {
let temp = a
a = b
b = temp
}
var a: Int = 6
var b: Int = 7
print("before a: \(a), b: \(b)")
swap(&a, &b)
print("after a: \(a), b: \(b)")
var c: Double = 3
var d: Double = 4
print("before c: \(c), d: \(d)")
swap(&c, &d)
print("after c: \(c), d: \(d)")
/* 결과
before a: 6, b: 7
after a: 7, b: 6
before c: 3.0, d: 4.0
after c: 4.0, d: 3.0
*/
2. 제네릭 타입
- 사용자 정의 타입 class, struct, enum이 어떤 타입과도 연관되어 동작할 수 있도록한다.
- EX) array, dictionary가 어떤 타입에도 동작하는 것과 같음
import UIKit
struct Stack<T> {
private var items: [T] = []
var count: Int {
return items.count
}
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T{
return items.removeLast()
}
}
var stack: Stack = Stack<Int>()
stack.push(item: 1)
stack.push(item: 2)
stack.push(item: 3)
stack.push(item: 4)
for i in 0 ..< stack.count {
print(stack.pop())
}
/* 결과
4
3
2
1
*/
3. 제네릭 타입 확장
- 제네릭을 사용하는 사용자 정의 타입을 extension을 통해 확장하려고 할 때, extension에 타입 매개변수를 명시하지 않아야함.
- 원래 제네릭 정의에 명시한 타입 매개변수는 extension에서도 사용가능
import UIKit
struct Stack<T> {
private var items: [T] = []
var count: Int {
return items.count
}
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T{
return items.removeLast()
}
}
extension Stack {
func first() -> T? {
return items.first
}
}
var stack: Stack = Stack<Int>()
stack.push(item: 1)
stack.push(item: 2)
stack.push(item: 3)
stack.push(item: 4)
if let first = stack.first() {
print("first: \(first)")
}
for i in 0 ..< stack.count {
print(stack.pop())
}
/*결과
first: 1
4
3
2
1
*/
4. 타입 제약
- 제네릭에 들어갈 타입 파라미터가 특정 타입에 한정되어야 하는 경우 제약을 걸 수 있다.
- 타입 제약은 'class' 혹은 'protocol'로만 줄 수 있다.
- struct, enum은 불가능
- <플레이스홀더: 타입 제약> 과 같은 방식으로 사용가능
- 제약을 여러 개 추가하고 싶다면 타입 정의 시 where문을 이용하여 where T: BinaryFloating과 같은 방식으로 사용 가능
import UIKit
protocol Number {}
protocol Swappable {}
extension Int: Number, Swappable {
}
func swap<T: Number> (a: inout T, b: inout T) where T: Swappable {
let temp = a
a = b
b = temp
}
var a: Int = 10
var b: Int = 5
print("before a: \(a), b: \(b)")
swap(&a, &b)
print("after a: \(a), b: \(b)")
/* 결과
before a: 10, b: 5
after a: 5, b: 10
*/
5. 프로토콜의 연관 타입
- 프로토콜을 정의할 때 연관 타입을 통해, '종류는 알 수 없지만 쓰일 타입' 에대해서 정의해줄 수 있다.
import UIKit
protocol Stack {
associatedtype T
var items: [T] {get set}
mutating func push(item: T)
mutating func pop() -> T
}
struct IntStack: Stack {
var items: [Int] = [] //자연스럽게 T = Int 타입으로 선언됨
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
struct DoubleStack: Stack {
typealias T = Double //typealias로 선언해줄 수도 있음
var items: [T] = []
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
6. 제네릭 서브스크립트
- 서브스크립트에도 제네릭을 활용할 수 있음
import UIKit
struct CustomArray<T> {
private var items: [T] = []
subscript<Indices: Sequence>(indices: Indices) -> [T] where Indices.Iterator.Element == Int {
var result = [T]()
for i in indices {
result.append(self.items[i])
}
return result
}
}
728x90
'Swift' 카테고리의 다른 글
[Swift] where절 (0) | 2021.05.31 |
---|---|
[Swift] inout 파라미터 (0) | 2021.05.28 |
[Swift] 이니셜라이저 (Initializer) (0) | 2021.05.28 |
[Swift] 옵셔널 추출 (Optional Unwrapping) (0) | 2021.05.05 |
[Swift] Selector (0) | 2021.04.22 |
댓글