//아래와 같이 같은 기능을 구현하고 있지만 타입이 달라 3개의 메소드를 각각 정의해줘야 했다.
//제네릭은 아래와 같은 문제들을 해결해, 재사용 가능한 코드들 작성하게 한다.
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoStrings(_ a: inout String, _ b: inout String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
let temporaryA = a
a = b
b = temporaryA
}
플레이스 홀더인 임의의 타입을 선언해 사용가능
//T라는 플레이스홀더를 생성해 사용하는 함수
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
//사용
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString is now "world", and anotherString is now "hello"
element간에 상관관계가 있는 경우 이름 파라미터
아닐경우 T, U, V 같은 대문자 파라미터를 관행적으로 사용
함수외에서 class나 struct 등의 타입에서도 사용 가능
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
지정하는 제네릭 타입이 특정 클래스를 상속 또는 프로토콜을 따르도록 제한하는 기능
//T는 SomeClass를 상속해야하며,
//U는 SomeProtocol을 따라야만 사용할 수 있다.
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// function body goes here
}
프로토콜에서 타입에 플레이스홀더를 부여하여 사용할 수 있는 기능
protocol Container {
//아래와같이 지정하여 프로토콜 내부에서 타입으로 사용가능
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
//사용예시: Int로 사용
struct IntStack: Container {
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
typealias Item = Int
mutating func append(_ item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
//사용예시: 제네릭 타입을 사용
struct SomeContainer<Some>: Container {
var items: [Some] = []
mutating func append(_ item: Some) {
items.append(item)
}
var count: Int = 0
subscript(i: Int) -> Some {
return items[i]
}
typealias Item = Some
}
//Associated Types에 조건걸기
//where 구문을 이용해 Suffix의 Item과 Item이 동일해야한다는 조건정의
protocol SuffixableContainer: Container {
associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
func suffix(_ size: Int) -> Suffix
}
where 절의 경우에 가끔가다 라이브러리 코드에서 보긴 했는데, 아직 구현이 자유자제로 필요할 때 쓰지 못하는 기능인 것 같다.
함수에서 Where
C1과 C2 타입이 같고 C1이 Equatable 일 경우 사용 가능
func allItemsMatch<C1: Container, C2: Container>
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
where C1.Item == C2.Item, C1.Item: Equatable {
if someContainer.count != anotherContainer.count {
return false
}
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
return true
}
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
protocol ComparableContainer: Container where Item: Comparable { }
#학습에 대한 내용으로 틀린 내용이 있을 수 있습니다.
#댓글로 남겨주시면 더 좋은 게시글로 수정하도록 하겠습니다.