[Swift] 제네릭
참조 : Swift 스위프트 프로그래밍 3판 Swift 5, 저자 야곰 (한빛미디어) , The Swift Programming Language Swift 5.6 Edition
(iBooks)(https://books.apple.com/kr/book/the-swift-programming-language-swift-5-6/id881256329)
제네릭(Generic)
- 스위프트 표준 라이브러리 또한 수많은 제네릭 코드로 구성
- 스위프트의 강력한 기능 중 하나
- 제네릭으로 구현한 기능과 타입 → 재사용하기 쉬움, 깔끔하고 추상적인 표현 가능
- Array, Dictionary, Set등의 타입은 모두 제네릭 컬렉션
- 제네릭을 사용할 때는 제네릭이 필요한 타입 또는 메서드의 이름 뒤의 (<>)에 제네릭을 위한
타입 매개변수를 써 제네릭을 사용할 것을 표시
- Array 타입 매개변수 : Element, map 메서드의 타입 매개변수 : T
→ Array는 제네릭 타입, map 메서드는 제네릭 함수
제네릭 함수
- 같은 타입인 두 변수의 값을 교환한다는 목적을 타입에 상관없이 할 수 있도록 단 하나의 함수로 구현 가능
- 제네릭을 사용한 swapTwoValue(_:_:) 함수
func swapTwoValue<T>(_ a: inout T, _ b: inout T) {
let temporaryA: T = a
a = b
b = temporaryA
}
var numberOne: Int = 5
var numberTwo: Int = 10
var stringOne: String = "A"
var stringTwo: String = "B"
var anyOne: Any = 1
var anyTwo: Any = "Two"
swapTwoValue(&numberOne, &numberTwo)
print("\(numberOne), \(numberTwo)") // 10, 5
swapTwoValue(&stringOne, &stringTwo)
print("\(stringOne), \(stringTwo)") // B, A
swapTwoValue(&anyOne, &anyTwo)
print("\(anyOne), \(anyTwo)") // Two, 1
※ 같은 타입끼리만 교환 가능
- 실제 타입 이름(Int, String 등)을 써주는 대신에 플레이스홀더(Placeholder, 위 함수에서는 T)를 사용
- 플레이스홀드(T)는 타입의 종류를 알려주지 않지만 말 그대로 어떤 타입이라는 것은 알려줌
- 플레이스홀더 타입이 T인 매개변수가 있음 → 두 매개변수는 같은 타입임
- Int 타입의 변수가 전달인자로 전달됨 → T는 Int
- String 타입의 변수가 전달인자로 전달됨 → T는 String
- 플레이스홀더를 지정하는 방법 : <> 안에 플레이스홀더 이름들을 나열, 여러 타입의 매개변수를 지정 → <T, U, V>
- 타입 매개변수를 지정 → 함수의 매개변수, 반환 타입, 내부 변수의 타입 지정을 위해 사용 가능
제네릭 타입
- Stack : 배열과 유사하게 순서가 있는 값들의 모임, 제네릭 컬랙션 타입 중 하나
- Stack은 컬렉션의 끝 부분에서만 요소를 추가하고 삭제할 수 있음
- 추가를 Push, 삭제를 Pop이라고 칭함
struct Stack<Element>{
var items = [Element]()
mutating func push(_ item: Element){
items.append(item)
}
mutating func pop() -> Element{
return items.removeLast()
}
}
var doubleStack: Stack<Double> = Stack<Double>()
doubleStack.push(1.0)
print(doubleStack.items) // [1.0]
doubleStack.push(2.0)
print(doubleStack.items) // [1.0, 2.0]
doubleStack.pop()
print(doubleStack.items) // [1.0]
→ items 배열의 타입을 Any로 지정 (Element)
타입 제약(Type Constraints)
- 타입 매개변수가 가져야 할 제약사항을 지정하는 방법
- 클래스 타입 또는 프로토콜로만 줄 수 있음 → 열거형, 구조체 등의 타입은 사용 불가
- 여러 제약 조건을 추가하고 싶다면 where절을 사용
- 제네릭의 타입제약 추가
func swapTwoValues<T: BinaryInteger>(_ a: inout T, _ b: inout T) where T:
FloatingPoint{
// 함수 구현
}
- 타입 제약에 자주 사용하는 프로토콜 : Hashable, Equatable, Comparable, Indexable, IteratorProtocol, Error, Collection 등
프로토콜의 연관타입(Associated Type)
- 어떤 타입이 들어올지 모를 때, 타입 매개변수를 통해 '종류는 알 수 없지만, 어떤 타입이 여기에 쓰일 것이다'라고 표현
→ 연관 타입은 타입 매개변수의 그 역활을 프로토콜에서 수행할 수 있도록 만들어진 기능
- Container 프로토콜
protocol Container{
associatedtype Itemtype
var count: Int {get}
mutating func append(_ item: Itemtype)
// mutating : 해당 메서드가 인스턴스 내부의 값을 변경한다고 명시할 때 사용
subscript(i: Int) -> Itemtype {get}
}
- Container 프로토콜을 준수하는 타입
- 컨테이너의 새로운 아이템을 append(_:) 메서드를 통해 추가
- 아이템 개수를 확인하기 위해 count 프로퍼티 구현
- Int 타입의 인덱스 값으로 특정 인덱스에 해당하는 아이템을 가져올 수 있는 서브스크립트 구현
- Container 프로토콜을 준수하는 MyContainer 클래스 정의
class MyContainer: Container {
var items: Array<Int> = Array<Int>()
var count: Int{
return items.count
}
func append(_ item: Itemtype) {
items.append(item)
}
subscript(i: Int) -> Int {
return items[i]
}
}
- IntStack 구조체의 Container 프로토콜 준수
struct IntStack: Container{
var items = [Int]()
mutating func push(_ item: Int){
items.append(item)
}
mutating func pop(_ item: Int) -> Int{
return items.removeLast()
}
mutating func append(_ item: Itemtype) {
self.push(item)
}
var count: Int{
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
'iOS > Swift' 카테고리의 다른 글
[Swift] NotificationCenter (0) | 2023.04.16 |
---|---|
[Swift] Localizable (0) | 2023.03.18 |
[Swift] for문 (0) | 2023.02.07 |
[Swift] UnsafePointer, UnsafeMutablePointer (0) | 2023.01.08 |
[Swift] 소수점 없애기 (0) | 2023.01.01 |