제네릭
제네릭은 같은 타입인 두 변수의 값을 교환한다는 목적을 타입에 상관없이 할 수 있도록 단 하나의 함수로 구현가능하다.
제네릭을 사용하고자 할 때는 제네릭이 필요한 타입 또는 메서드의 이름 뒤에 <> 사이에 제네릭을 위한 타입 매개변수를 써주어 제네릭을 사용할 것임을 표시한다.
제네릭을 사용하고자 하는 타입 이름 <타입 매개변수>
제네렉을 사용하고자 하는 함수 이름 <타입 매개변수> (함수의 매개변수..)
fucn swapTwoValues<T>(_ a: inout T, _ b: inout T) { //T는 플레이스홀더
let temporaryA: T = a
a = b
b = temporaryA
}
swapTwoValues(&numberOne, &numberTwo)c. //&numberOne, &numberTwo 미리 지정 되어있다는 가정.
위처럼 같은 타입만 교환 가능
위 함수처럼 타입명에 플레이스 홀더(대부분 알파벳 대문자 한 글자)를 사용함으로써 호출될때마다 다른 타입으로 활용할 수 있다.
stack은 제네릭 컬렉션 타입 중 하나다.
스택은 배열과 유사하게 순서가 있는 값들의 모음이다. 그러나 배열과는 다르게 컬렉션의 끝 부분에서만 요소를 추가 및 삭제가 가능하다. 추가는 푸시, 삭제는 팝이라고 한다.
모든 타입을 대상으로 동작되는 스택을 구현하기 위해서는 타입을 Any로 지정해주면 되지만, 요소로 한 타입을 지정해주면 계속 그 타입으로 스택이 동작하길 바란다면 제네릭을 사용하여야 한다.
Struct Stack<Element> { //<>으로 제네릭 타입을 정의함으로써 첫 번째 입력한 타입으로 고정된다.
var items = [Element]()
.
.
.
}
익스텐션을 통한 제네릭을 사용하는 타입에 기능을 추가하고자 한다면 익스텐션 정의에 타입 매개변수를 명시하지 않아야 한다.
extension Stack { //Stack은 제네릭 타입이지만 따로 명시하지 않는다.
var topElement: Element? { //제네릭 타입에 정의되어 있는 Element는 사용할 수 있다.
return self.itme.last
}
}
제네릭 함수가 처리해야할 기능이 특정 타입에 한정되어야만 하거나, 특정 프로토콜을 따르는 타입만 사용하도록 제약을 두어야만 하는 상황이 생겼을경우 타입 제약을 사용한다.
func A<T: BinaryInteger>( ...) //타입 매개변수(T) 뒤에 : 과 함께 제약조건으로 주어질 타입을 명시한다.
제네릭은 어떤 타입이 들어올지 모를 때, 타입 매개변수를 통해 종류는 알 수 없지만 어떤 타입이 여기에 쓰인다. 라는 형식으로 쓰였지만,
연관 타입은 타입 매개변수의 그 역할을 프로토콜에서 수행할 수 있도록 만들어진 기능이다.
서브스크립트도 제네릭을 활용하여 타입에 큰 제한 없이 구현 가능하다. 타입 제약도 사용가능하다.