조앤의 기술블로그
[Swift] Generics (제네릭) 본문
제네릭을 사용하면 함수를 작성하고, 어떠한 타입과도 동작할 수 있게 해줍니다.
코드의 중복을 피할 수 있기 때문에, 유연하고(flexible), 재사용성(reusable)이 높은 코드를 작성할 수 있습니다.
제네릭은 스위프트의 가장 큰 특징 중 하나입니다. 그리고 스위프트의 많은 standard library가 제네릭으로 작성되어 있습니다.
(Array, Dictionary...)
[제네릭으로 해결할 수 있는 문제점]
예를 들어 swap함수를 생각해보겠습니다.
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let tmp = a
a = b
b = tmp
}
이 함수로는 Int 형의 두 수만 swap할 수 있습니다.
String형, Double형의 값을 swap하려면 각각 자료형에 맞는 함수를 새로 생성해야 합니다.
func swapTwoStrings(_ a: inout String, _ b: inout String) {
let tmp = a
a = b
b = tmp
}
func swapTwoDouble(_ a: inout Double, _ b: inout Double) {
let tmp = a
a = b
b = tmp
}
이는 함수 코드의 중복 문제점, 그리고 코드가 수정될 경우 모든 함수의 코드를 수정해야 한다는 문제점이 있습니다.
제네릭을 이용하여 이 문제를 해결할 수 있습니다.
[Generic Functions]
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let tmp = a
a = b
b = tmp
}
제네릭 함수는 어떤 타입과도 실행될 수 있습니다.
var someInt = 93
var anotherInt = 309
swapTwoValues(&someInt, &anotherInt)
var someString = "Happy"
var anotherString = "Birthday"
swapTwoValues(&someString, &anotherString)
[Type Parameters]
T를 타입 파라미터라고 합니다.
타입 파라미터 T는 실제 자료형으로 대체되는 placeholder입니다.
[Generic Types]
스택 구조체를 만들어 예시를 보겠습니다.
struct IntStack {
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
이 구조체는 Int형만 스택에 push, pop할 수 있습니다.
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutaing func pop() -> Element {
return items.removeLast()
}
}
같은 코드로 <Element>타입 파라미터로 대체하여 만든 stack 구조체입니다.
Element 파라미터에 어떠한 형식이든 올 수 있습니다.
var stackOfStrings = Stack<String>()
stackOfStrings.push("하나")
stackOfStrings.push("둘")
stackOfStrings.push("셋")
stackOfStrings.push("넷")
let fromTheTop = stackOfStrings.pop()
[Associated Types]
프로토콜을 선언할 때 제네릭을 사용하려면 'associatedtype' 이라는 키워드를 사용합니다.
선언된 형식은 프로토콜 형식 내에서 실제 형식으로 대체되는 placeholder입니다.
Container 프로토콜을 선언하겠습니다.
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
아까의 Stack 구조체에 Container프로토콜을 채용해보겠습니다.
struct Stack<Element>: Container {
//original Stack<Element> implementation
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
//conformance to the Container Protocol
//typealias Item = Element
// 형식 추론으로 타입이 추론되기 때문에 생략해도 됩니다.
mutaing func append(_ item: Element){
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
associatedtype Item에 Element가 대입되었습니다
'Study > Swift' 카테고리의 다른 글
[Swift] Protocol (프로토콜) #1 (0) | 2020.03.04 |
---|---|
[Swift] Extension (익스텐션) (0) | 2020.02.27 |
[Swift] Initializers #2 (0) | 2020.02.26 |
[Swift] Initializers #1 (0) | 2020.02.26 |
[Swift] Type Casting (타입 캐스팅) (0) | 2020.02.25 |